Tuesday, May 8, 2012

Why you should use git merge --no-ff when rebasing.

When working with Git my normal workflow was to create my feature/bugfix in a branch. When I'm ready to integrate it, I rebase the branch and merge it into master. This ensures that the master branch has a linear history.

This gives you a clean history which is easy to bisect.
An example of linear history
However, when reading the help for git merge I came across the --no-ff parameter. It says:
Create a merge commit even when the merge resolves as a fast-forward.
I decided to use it for my 0.2 version of my software. This created the following graph in gitk:
Branche rebased and merged with git merge --no-ff
This code was first rebased, then merged with git merge --no-ff. An explicit merge commit is now created (where the tag 0.2 points to). Because the branch was already rebased, this merge commit does not contain a diff - it only exists to merge the two branches together.

This gives you several advantages on top of the advantages you have using git rebase:
  1. You can see the name of the branch you merged back into master.
    The name is part of the commit message of the merge commit.
  2. In the graph you can easily see what commits were part of the branch. 
    This comes in handy when you later want to see what individual commits were needed to create a specific feature branch.
  3. You are now able to revert the entire branch by reverting the merge commit with git revert.
    Beware that the git revert commit command needs to know that you are reverting a merge. In the example above I would revert it with 'git revert -m 1 0.2'. See the git man page for details.
Enough advantages for me to keep on using the rebase workflow but to merge it with an explicit merge commit.

1 comment:

  1. Full disclosure I am an aggressive rebaser. As such I have encountered the `no-ff`er before. Its totally cool if you want to do it, but the reality is that its a relic to support the workflows of old version control tools. In the majority opinion git-verse branches are not meant to be left open indefinitely(in fact the preferred github workflow is to delete them after merge ... gasp). Developers and product folk should be encouraged to keep changes small enough that the result in less than ~200 lines. Now if your commit is only 200 lines is it necessary to keep copious history or even the branch that resulted in the change. So with this in mind lets look at your points 1 by 1.

    1. you can see the name of the branch. The branch is gone-zo so this no longer applies.

    2. You can see what commits were part of the branch. Unnecessary the change was only one commit

    3. you can revert the entire branch by reverting the merge commit . Covered by number two.

    So I know your going to come back to with some this or that about the time when you needed to edit 25,000 lines of code and in those cases maybe `no-ff` is appropriate. But I don't know because its literally been years since I checked in a change over a few hundred lines and the vast majority of my changes are less than 50 and the even vaster majority are between 1 and 5. So I'd say if you find the feature to be an important part of your workflow maybe you are doing something wrong.

    ReplyDelete