Git: How to consistently maintain local patches

We thought it’s time to share some tech and talk code! This post will explain a problem when dealing with “workaround” branches in Git.
Here is the situation: Imagine your local machine is a bit different than those of your colleagues or – as in our case – there are different prototypes of your product lying on the table. Here at SUPENTA we work with NFC technologies. Turns out the NFC tag I worked with had slightly different specs than the tag that might go in the final product. In both cases (different machines or different tags), one developer might have to change the code base slightly in order to make it work locally. Of course, these changes are only temporarily and should not affect the upstream code base.

So this is the situation: You want to maintain your local changes and still be able to fetch and push upstream patches. But you don’t want your “workaround” patches to go upstream. In this post, I will explain how you can achieve this using git cherry-pick.

The Setup

Let’s suppose you have cloned a fresh copy of the upstream repository. The commit history might look like this:


A fresh clone of the repo


As you can see, we have only three commits in the master branch. Now, we’ll add the local patch (or patches) in a new branch which we do not want to push:
> git checkout -b workaround
> hack hack hack
> git add .
> git commit -m "Added Workaround"

The above commands result in the following picture:


Added your local workaround


Doing acutal work

So now that we’re settled and everything works locally, we can do some actually work. The following picture illustrates the state of our local repository after adding two patches:


Added two patches to the workaround branch



Talking to the rest of the team

This is where it gets interesting. Until here, everything was nice and easy. Now, we face two challenges. First, we need to track upstream changes and incorporate them in our workaround branch. Secondly, we want to share the Z and Y patches with the rest of the world. First things first: Let’s get the latest changes from upstream and merge them into the local master branch. This is going to be fast-forward because we didn’t touch that branch:
> git checkout master
> git pull origin

Supposing someone else pushed D and E in the meantime, the result looks like this:


Fetched upstream patches



Due to the handicap on our local machine, we actually need to merge the local master in the workaround branch and not the other way around:
> git checkout workaround
> git rebase master

You could also use git merge master depending on your taste. Learn about the difference here. Make sure to resolve all conflicts and test that everything still works locally.


Merged/rebased upstream patches


We now have the latest upstream patches and all our local patches in the workaround branch. Now, let’s checkout the master branch and git cherry-pick everything we need:
> git checkout master
> git cherry-pick z
> git cherry-pick y

If you have a whole bunch of patches, you can also use git cherry-pick <fromSHA1>..<toSHA1>. In our case, we make sure to pick Z before Y to keep track of functional dependencies. This is what it looks like afterwards:


Cherry-picked what should go upstream


Be proud of your work and tell the world about it:
> git push origin


Pushed Z & Y upstream


This is pretty much it. Remember to check out your workaround branch again. In order to keep things clear, it’s best to rebase the master branch again. Git will recognise that the commits are identical and just replay your workaround patch(es) on top of it:
> git checkout workaround
> git rebase master



Make sure to follow this recipe (adapted your needs, of course) step-by-step. I was tempted to automate parts of it but eventually dismissed the idea because it was too much overhead. However, to have something reproducible I use a bash script as my tutor:


echo “NOW: git checkout master”
echo “NOW: git pull origin/master”
echo “NOW: git checkout workaround”
echo “NOW: git rebase master”

This enables me to remember where I was even when the rebase/merge took some time or lunch was ready 😉
Furthermore, I used git format-patch -1 <workaround-sha1> to have a copy of the workaround patch. I put this file somewhere save to be able to reproduce my local branch if anything went wrong.

I hope this helps some of you out there and I will be more than happy to receive your comments on this.



Have something to add?

Loading Facebook Comments ...

Leave a Reply