8

We are now in the process of switching from svn to git (after a year spent on convincing people, yay!) in my company.

So far, this is all for the better but there is one little thing that we currently have in our workflow that I can't find a good equivalent too.

Currently, all our developers work in master. Once every quarter, we branch master into X.x branch, which will later on become our latest release. This means that our svn repo looks like this:

  • trunk
  • branches
    • 3.8
    • 4.1
    • 4.2
    • ...

We don't really use tags.

Once in a while, there is an urgent bug fix that is discovered.

The current way for us to do it is:

  • Fix it in master
  • SVN merge the relevant range of commits back into the relevant branches (Maybe our latest release, maybe more).

We are in the space industry, so our branches are long lived and the customer upgrade process is rather long, which is why we have worked like that so far.

Now, how would be a good equivalent in git?

So far, I have tried to fix the bug in a branch spawned from master, and then merge this branch back in master and in 4.3 (for example). Thing is, the hotfix branch contains the master history, and all the commits between master and 4.3 get merged as well, which we don't want to.

Things I could think of so far:

  • I have looked at the very successful Git Workflow method, and their solution is to fix the bug in the release branch and merge it back instead of the other way around. This could work in our case, but would be rather cumbersome because it would require us to already know the oldest branch we want to fix the bug in before actually fixing the bug.
  • Another solution is to fix in master, and then cherry pick the commits (as we do for the svn merge today). The annoying thing here is that in this case we lose history of what has been merged back where, since cherry picks look like new commits and we lose the relationship.

So what is the "good" way to do it? Should we fix commits in history, or cherry pick and manually keep track of what has been merged, or even something else?

If have little production experience with git, so I am sure I may have missed something.

8

The Git Flow assumes you only have a single supported release, with the master branch always pointing to the latest release. Since you support multiple releases simultaneously, you cannot copy that workflow 1:1. Nvie's Git Flow is a very good example of a branching strategy, but you must adapt it to your needs. Most importantly, you will have multiple active release branches.

When you identify a bug, you will have to do some testing to determine all affected versions. It is not sufficient to write the fix first, then merge it back into the release branches as a hotfix. Usually, you'll end up with some continuous range of affected versions. Very old versions might not contain the bug, newer versions might have gotten that bug fixed accidentally. You will need to verify the bug on each version so that you can verify it is actually gone after the fix. If you can express the bug as an automated testcase, it's pretty straightforward to find the problematic commit via git bisect, or to run the test for each release:

for release in 3.8 4.1 4.2
do
  git checkout $release
  if ./testcase >release-$release.log
  then echo "$release ok"
  else echo "$release AFFECTED"
  fi
done

Now, you used to write the fix on trunk/master. This is problematic because the buggy part may have changed between versions, so a patch will not usually apply to an older version. In particular, code in master might depend on any features available in master, which might not have been present in older versions. It therefore makes a lot of sense that a Git commit references its whole history, not just the change set. When merging back, it will pull in all the history it depends on.

Using cherry-pick or rebase ignores this history, and records a new commit with the same changeset, but a different history. As pointed out, this will not work if your codebase has diverged.

The “correct” solution is to write the fix as a hotfix on the oldest affected release. Then, you merge oldest release into the second-oldest release. Usually, a newer release would contain all commits of an older release, so this is OK. If things have changed, you now have a chance to manually resolve the merge conflict. Then you continue merging each release into the next-younger release until you are done. This maintains proper history and avoids a lot of unnecessary work, while only requiring effort that has to be expended anyway. In particular, this incremental merging gets you closer to the current development state in small steps.

As a diagram:

| o normal commit |
| x hotfix        |
| ⇘ merging       |

3.8 --o-----------------x
       \                 ⇘
4.1     o--o--o-----------x'
               \           ⇘
4.2             o--o--o-----x''
                       \     ⇘
develop                 o--o--x'''--o--o
  • 1
    For completeness, let's say the test was a little wrong and version 3.7 has the same bug (say, it only happens on an edge case in 3.7, but happens in more easily-tested cases in 3.8+), but was only discovered after the fix was merged like this. Would you just cherry-pick at that point? – Izkata Dec 17 '15 at 21:13
  • 1
    @Izkata yes, at that point it's no longer possible to pretend that there's any kind of sensible history, so cherry picking is a good way to apply the changes to an older release. However, this implies that the release branches have diverged, and newer releases no longer contain all commits of older releases. Therefore, we should do the merge chain again from the release we changed up to the development branch. However, during the first merge we can discard the cherry-picked changes since we had already applied the fix to the newer release. – amon Dec 17 '15 at 22:29
  • Thanks for you answer @amon. Your answer is very complete, and going in the direction I was looking at already, so It is good to have validation. We will take on our own industry requirements and adapt the git flow approach to something that will fit us better. Thanks again! – jlengrand Dec 18 '15 at 14:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.