DevOps Zone is brought to you in partnership with:

Ariya is a passionate engineer interested in bleeding-edge technologies. He has been involved in various large projects, from KDE to WebKit. These days, his focus is mostly on software craftsmanship around web technologies. His (little) spare time is spent running the projects PhantomJS (headless WebKit) and Esprima (JavaScript parser). Ariya is a DZone MVB and is not an employee of DZone and has posted 58 posts at DZone. You can read more from them at their website. View Full User Profile

Fast-forward Git Merge

09.24.2013
| 6769 views |
  • submit to reddit

Merging a branch is a pretty common operation when using Git. In some circumstances, Git by default will try to merge a branch in fast-forward mode. How is this different from a merge without fast-forwarding?

gitbranch Let's assume that I created a topic branch named speedup from the current master. After working on this branch for a while (three commits, those white circles), I finally decided that I was done and then I pushed it to my own remote. Meanwhile, nothing else happened in the master branch; it remained in the same state right before I branched off. The situation is depicted in the following diagram.

Once the project maintainer was notified that my branch was ready to be integrated, she might use the usual steps of git fetch followed by git merge and thus, my work lands in the source tree. Because the master has not been changed since the commit (gray circle), which serves as the base for the said topic branch, Git will perform the merge using fast-forward. The whole series of the commits will be linear. The history will look like the diagram below (left side).

merging

Another variant of the merge is to use the -no-ff (no fast-forward) option. In this case, the history looks slightly different (right side); there is an additional commit (dotted circle) emphasizing the merge. This commit even has the right message informing us about the merged branch.

The default behavior of Git is to use fast-forwarding whenever possible. This can be changed; no fast-forward mode can be easily set as the default merge using the proper configuration.

Perhaps a typical example of a non-fast-forward merge is via the use of the green merge button on GitHub, as part of its pull request workflow. When someone creates a pull request, there is a choice to merge the change (whenever GitHub thinks it is possible to do so) by just pressing this button on the project page.

automerge

Unfortunately, at least as of now, GitHub’s web interface will perform the merge as if you specified -no-ff. In other words, even if there is a possibility of fast-forwarding, GitHub will not do so. One possible explanation is so that the pull request could be identified. For example, the few recent commits of a project (I picked ESLint as an example, nothing particular about the project) can look like this:

nonlinear

Looking at the graph, it is clear that those few patches can be merged using fast-forward mode. Alas, the GitHub style of merging turned the commit history from a linear progression to something that resembles a railroad diagram.

In short, non-fast-forward merging keeps the notion of explicit branches. It may complicate the commit history with its non-linear outcome at the price of preserving the source of the branches (pull requests, when using GitHub). On the other hand, fast-forward merging keeps the changesets in a linear history, making it easier to use other tools (log, blame, bisect, etc.). The source of each branch will not be obvious, although this is not a big deal if the project mandates the strict cross-reference between the commit message and its issue tracker.

Which one is your merging preference, with or without fast-forwarding?



Published at DZone with permission of Ariya Hidayat, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)