Patching Tools - St

2020-07-12


As part of my renewed dotfiles setup and dev box setup, I’m taking the opportunity to update my core suckless.org tools: st, dwm, dmenu.

I’ve been using these for some time, and it’s great for me to be able to customize tools I use.

In this post, I’ll re-create a new ST fork using up to date code base, and new patches that will work for me.

Note: The focus will be on branching strategy and resolving merge conflicts. The aim is to show an effective way to leverage git and merge tools to integrate patches. You may want to read my previous post describing how merge conflicts can be resolved using tools.

initial setup

As you may know, git is a distributed version control system that can sync with multiple remotes.

To get started, I usually:

  1. create my own git repository
  2. clone this repository locally (origin)
  3. define an upstream remote
  4. merge the upstream/master branch into my local master branch
  5. update my remote origin

Lets do this:

1
2
3
4
5
6
git clone git@github.com:benoitj/st.git
cd st
git remote add upstream https://git.suckless.org/st
git fetch upstream
git merge upstream/master
git push

The resulting remote setup is:

1
git remote -v

and my current branch setup:

1
git branch -a -vv

You can see that my local master branch tracks my github’s origin/master branch.

Patching strategy

For each patch, I will:

  1. create a branch from the commit the patch was created from.
  2. apply the patch. We should not get conflicts here.
  3. merge the patch to master branch (may need conflict resolution. Read my previous post)

How do we know how to create the branch?

In the case of most patches, the filename indicate some context. In the following example, we will apply the patch st-xresources-20200604-9ba7ecf.diff. From the file name, we understand the patch was created June 4th from the commit hash 9ba7ecf.

Now the trick is to create our branch from that commit. Reading the git documentation, you can learn this is done with the syntax: git branch [commit hash]

Sometimes the commit hash does not match the history, in this case, use git log and find a commit hash close to the patch creation date.

Patching ST

Lets do this and apply the patch:

1
2
3
4
5
mkdir patches
wget -P patches https://st.suckless.org/patches/xresources/st-xresources-20200604-9ba7ecf.diff
git branch patches/xresources 9ba7ecf
git checkout patches/xresources
git apply < patches/st-xresources-20200604-9ba7ecf.diff

And we can see what has changed:

1
git diff

and lets confirm it worked:

1
2
make clean all
./st

Everything’s good, now is a good time to commit our changes:

1
2
git add x.c config.def.h patches
git commit -m "applying patch st-xresources-20200604-9ba7ecf.diff"

And push:

1
git push --set-upstream origin patches/xresources

and merge the branch to master:

1
2
git checkout master
git merge patches/xresources

I will do the same for the following patches: externalpipe and scrollback:

1
2
3
4
5
wget -P patches https://st.suckless.org/patches/scrollback/st-scrollback-20200419-72e3f6c.diff
git branch patches/scrollback 72e3f6c
git checkout patches/scrollback
git apply < patches/st-scrollback-20200419-72e3f6c.diff
make clean all
1
2
3
git add st.c st.h config.def.h patches
git commit -m "applying patch st-scrollback-20200419-72e3f6c.diff"
git push --set-upstream origin patches/scrollback
1
2
git checkout master
git merge patches/scrollback

If I build master, I have both scrollback and xresources patches included:

1
2
rm config.h
make clean all

Merge conflicts

You may get couple of merge conflicts around keybindings, configuration, and similar.

They are usually really simple to solve using a merge tool as described in this previous post.

I had no conflict patching st, but had some when patching dmenu. Here are some examples:

Example of applying borderoption patch on top of border patch

1
2
3
4
5
git checkout master
git merge patches/border
git merge patches/borderoption
git mergetool
git commit

Example of such conflict when merging border and borderoption on dmenu master branch:

In this case, I will select the remote (the borderoption branch) since it makes the attribute mutable.

Example of applying the dmenu fuzzymatch patch on top of center patch

1
2
3
4
5
git checkout master
git merge patches/center
git merge patches/fuzzymatch
git mergetool
git commit

In this case, we need to take both the local (center patch) and the remote (fuzzymatch patch), so I select C and B to get this result:

Thoughts and what’s next

I hope I was able to show how simpler patching tools can be when using a branching strategy, branching from the right version, and using tools to resolve conflicts.

Yes you can do all this manually on the same branch, but it’s takes more time and it is much more error prone. Tools are better than us to identify patterns and repeat tasks.

Have fun patching! :)


This is day 10 of my #100DaysToOffload. You can read more about the challenge here: https://100daystooffload.com.