When to use the '--no-ff' merge option in Git

Solution 1:

It's really dependent on what you're trying to do. My rule of thumb is that if the merge "means something" I use the --no-ff option. When the merge doesn't really mean anything and you might have used a rebase there's no reason to use --no-ff.

The thing with git is that it's a very powerful tool, and you can use it in many ways - most of which are not wrong. Asking what's the "right way" to do it is like asking what's the right way to paint a picture.

At least for me it's an evolving set of ways I like to do it, with frequent discussions in the team of how we want to collaborate on the code - from this we try to derive a kind of "how it's done here" standard, but it's just our way of doing it.

Solution 2:

For the case of a finished branch with a single commit, don't use --no-ff, just fast-forward it, because the history will be much simpler and less cluttered. It's hard to argue that --no-ff gets you any advantages in this case, because it's uninteresting to see a parallel branch of development with just a single commit, vs a single commit in a sequential line:

# No fast-forward
$ git merge --no-ff awesome-feature
*   3aa649c Merge branch 'awesome-feature'
|\
| * 35ec88f Add awesome feature
|/
* 89408de Modify feature-001.txt and fix-001.txt
* c1abcde Add feature-003

# versus fast-forward
$ git merge awesome-feature
* 35ec88f Add awesome feature
* 89408de Modify feature-001.txt and fix-001.txt
* c1abcde Add feature-003

For the case of a finished branch with more than a single commit, it's up to you, whether or not you want to keep the fact that the branched development happened in parallel vs sequential. I would probably use --no-ff for more than one commit, just so that I can visually see this branched work, and so that I can manipulate it easily with a single git revert -m 1 <sha-of-merge-commit> if I had to.

# No fast-forward
$ git merge --no-ff epic-feature
*   d676897 Merge branch 'epic-feature'
|\
| * ba40d93 Add octocat.txt
| * b09d343 Add bye.txt
| * 75e18c8 Add hello.txt
|/
* 89408de Modify feature-001.txt and fix-001.txt
* c1abcde Add feature-003

# versus fast-forward
$ git merge epic-feature
* ba40d93 Add octocat.txt
* b09d343 Add bye.txt
* 75e18c8 Add hello.txt
* 89408de Modify feature-001.txt and fix-001.txt
* c1abcde Add feature-003

See how in this case of fast-forward merge, without additional information in the commit messages themselves, it's hard to tell that the last 3 commits actually belong together as one feature?