277

I can't really ever think of a time when I would use git merge rather than git rebase and not want to have a commit show up. Is there any way to configure git to have fast forwarding off by default? The fact that there's an --ff option would seem to imply that there's a way, but I can't seem to find it in the documentation.

Jason Baker
  • 171,942
  • 122
  • 354
  • 501
  • 3
    I use `merge` all the time for branches when haven't made any commits off their remote in order to fast-forward them. It seems the simplest and safest way to do this. I'm curious, you obviously have a use case. Why would you ever want to create a merge commit where there are no commits on one side of the branch? – CB Bailey Mar 23 '10 at 13:44
  • 12
    I use branches to create a logical grouping of commits. So if I make a merge, it's basically a way to say "these commits go together". You can almost think of it as a poor man's interactive rebase and squash. :-) – Jason Baker Mar 23 '10 at 14:48
  • 13
    Turning off fast forwarding is extremely useful, particularly when following a model like [A successful Git branching model](http://nvie.com/posts/a-successful-git-branching-model/) – steinybot Sep 19 '12 at 03:31
  • 2
    Please change the accepted answer for this to Eric Platon's answer http://stackoverflow.com/a/6810687/3408 - I did the steps in the accepted answer, then realised that it was only for the master branch in the current repository, which is silly. – rjmunro Oct 02 '15 at 09:12
  • @Steiny No, it just makes your repository a mess: http://endoflineblog.com/gitflow-considered-harmful. – jpmc26 Apr 07 '16 at 19:46
  • 4
    @jpmc26 Each to their own I guess. I happen to disagree with that article. Finding the two parents of a merge commit is not hard and tells you exactly what the changes were. Then you can take those changes and do a "rebase onto" some other branch. With the flat model you have to manually find and cherry pick. We choose to embrace branching. Sure it is complex when looking at the entire tree but that is the reality, multiple changes occurring in parallel. Flattening everything just hides what really happened. – steinybot Apr 07 '16 at 22:15
  • @Steiny Yes, it does hide "what really happened." And that's a good thing. It cuts out irrelevant details no one needs to care about and preserves the ones that are important; that's what good documentation does. Finding the parent of a single merge is not hard, true. Tracing back across 100 commits over 4 branches with a lot of criss crossing trying to figure out what actually changed and where does not seem especially easy, especially when those commits may or may not actually introduce changes to the code base. (This is what Gitflow recommends/requires.) – jpmc26 Apr 08 '16 at 01:03
  • 2
    @jpmc26 You are making claims that are very strong and biased, you literally said "No, it just makes your repository a mess" regarding this article http://nvie.com/posts/a-successful-git-branching-model/, while this Git workflow might not work for you, it works for some enterprise teams – Brian Ogden Oct 12 '17 at 22:29
  • I understand git config changes the settings per user. Is there a way to disable fast forwarding for the repository (for all users), creating a kind of "repository merge policy"? – Suma Oct 09 '18 at 07:47

4 Answers4

357

It seems there is still a pending question in the thread: How to do it globally (i.e. for all branches) ? For the records, we can use the following:

git config --add merge.ff false

...to make it apply to all branches in the current repository. To make it apply to all branches in all repositories where someone has not run it without the --global option (local settings override global) run this:

git config --global --add merge.ff false

From the documentation:

merge.ff
By default, git does not create an extra merge commit when merging a commit that is a descendant of the current commit. Instead, the tip of the current branch is fast-forwarded. When set to false, this variable tells git to create an extra merge commit in such a case (equivalent to giving the --no-ff option from the command line). When set to only, only such fast-forward merges are allowed (equivalent to giving the --ff-only option from the command line).

Kai
  • 752
  • 1
  • 13
  • 31
Eric Platon
  • 8,821
  • 6
  • 37
  • 45
  • 18
    Note: `merge.ff` was introduced in Git 1.7.6. It is not effective in older versions. – Chris Johnsen Jul 25 '11 at 04:06
  • 2
    For people using Git 1.7.6, this is the best and simplest solution. – Ryan Lundy Aug 31 '11 at 17:07
  • 22
    I'm using this together with an alias `puff = "pull --ff --ff-only"` – stigi Jun 27 '12 at 10:02
  • I really like the alias option, since your pulls won't result in a merge commit always. – pedromanoel Mar 20 '13 at 12:08
  • 11
    Theres is also (now, see http://git-scm.com/docs/git-config) the option _pull.ff_ which can be set to _only_, which will do the same as the alias. – jotomo Dec 13 '14 at 14:32
  • 1
    Thank you, @jotomo. That feature is available from Git v2.0.0 (from commit b814da891e8261b909fc5d9fb07b4e8b13989c2d). – Eric Platon Dec 15 '14 at 00:22
  • You could also use rebase for git pull, to prevent merge commits. Use `git pull --rebase` or configure it as default with `git config --global pull.rebase true`. If you have not made any commits, this works identically to `merge --ff`. If you have made some commits to the branch locally, but not pushed them, they will be added to the end of the branch, rather than merged in. This is usually what you want. – rjmunro Oct 02 '15 at 09:39
  • Is there a way to only make this apply when merging branches and not when doing a git pull? – wayofthefuture Sep 09 '17 at 16:48
  • For it to work on our systems i needed `git config --global --bool merge.ff false` (git version 2.20.1) – bigbear3001 Apr 12 '21 at 13:22
294

Yes, there is --no-ff. You can configure merge options per branch, e.g.

git config branch.master.mergeoptions  "--no-ff"

adds the following to your $(REPO)/.git/config file:

[branch "master"]
    mergeoptions = --no-ff

Footnote: speaking of my experience, I eventually found switching fast-forward to off was mostly helpful for git newcomers - however once the feel for workflows and concepts start to sink in you definitely want to avoid blurring your log graph with tons of pointless 'merged remote ..blarf' type commits.

Footnote 2, a decade later: the other answers below provide more modern config options, but really, you probably DO want to stay with the defaults (i.e. fast-forward whenever possible) in this day and age, because empty merge-commits really only make the history much more difficult to reason about.

conny
  • 9,012
  • 6
  • 35
  • 43
  • 152
    Learning git is a bit like mountain climbing; but instead of starting with small cliffs and progressing to tougher ones, git makes you climb the same mountain again and again, only to fall at different heights each time, every time just as surprised that the lifeline wasn't attached. – conny Mar 23 '10 at 15:52
  • 5
    Does this affect "git pull" and its merge strategy at all? – Tom Mayfield Jul 23 '10 at 19:51
  • 12
    @Thomas: Yes; `git pull` is `git fetch` + `git merge`. – Michelle Tilley Sep 04 '10 at 22:08
  • 9
    This looks good, but is there any way to do it globally, for all branches, instead of having to set it up for every branch? – bwinton Mar 10 '11 at 15:25
  • 34
    Beware of the dragons. This option is dangerous just as @Thomas said... Every git pull creates merge commit. git pull --ff doesn't override the mergeoptions=no-ff in git config. – Dalibor Filus Sep 15 '11 at 10:59
  • 6
    Regarding the footnote -- instead of 1 "pointless" "merged branch fiddle-around" commits -- we get the entire "fiddle-around" series of commits merged onto our master. Often including a half-dozen merge commits. If you have the merge commits, you can ignore the detailed feature commits, and get the big overview, like this: $ git log --first-parent --pretty=oneline'feature-1'" c605cca334c722a34e3aea88c36a043ab3cca741 Merge branch 'feature-2' f93a46a24bd0761da0a1bd64b2da0549980979c8 Merge branch 'feature-1' 163602263b4f0a8463c6de82d3a7dd7b4c04ebca project inception – Bob Kerns Sep 20 '12 at 15:41
  • [Beware of `--no-ff` - it can break `blame` and `disect`](http://stackoverflow.com/a/2850413/274502) – cregox Dec 02 '13 at 18:42
  • 16
    What if I'm just tired of typing `git merge --no-ff (branchname)`? And I want `git pull` to function as it always has? – Dogweather Feb 04 '15 at 07:10
  • 1
    You probably wouldn't want to set this up for your master branch. Where it's most useful is small feature branches, where you'd like to be able to see all the commits on that feature branch as distinct from other commits. – Ryan Lundy Aug 13 '15 at 21:52
  • 1
    If you want a non-fast-forward merge, use rebase. A fast forward merge is really a rebase as rebase naturally doesn't add merge commits. Set git pull to use rebase using `git pull --rebase` or configure it with `git config --global pull.rebase true` – rjmunro Oct 02 '15 at 09:23
  • This helped a lot! I would like to add for those who are interested you can also set other subcommand options by simply replacing the `--no-ff `with any other subcommand. I recently found this setting to be very beneficial. `git config branch..mergeoptions "--log"` To allow the `--log` subcommand to track in the merge commit the subject of all the commits being merged into the specified branch. – Eric Aug 25 '16 at 16:49
  • 3
    @DaliborFilus Tame the dragons: `git config branch.autosetuprebase always` This enables fast-forward for the master branch when pulling, even with `branch.master.mergeoptions "--no-ff"` – orzechow Apr 20 '17 at 21:46
  • Since Git 2.4.3 you can specify `pull.ff` (to true) config options to override `mergeOptions` for `pull` command. – Gendolph Mar 21 '18 at 10:18
  • FYI: This is just for the master branch, if you want for all branches you need @eric-platon's answer – Pylinux May 02 '18 at 11:56
  • Since nobody has mentioned this in the answer, I would like to add, that this option has side effects on how "git pull" works. I have experienced, that "git pull" will implicitly create a separate merge-commit, even though fast-forwarding the branch was possible. – Dennis Kassel Jun 03 '20 at 11:11
  • I believe that the peace of mind of knowing that you can undo any faulty merge with a simple `git reset HEAD~1` simply overtakes any inconvenience of always merging with a new commit. In fact, I'd mark (@eric-platon's)[https://stackoverflow.com/a/6810687/8699916] answer as correct. By doing what he says, `pull` stays the same. – ppicom Apr 15 '21 at 14:26
20

Reading the thread of answers I ended up using the following two options

git config --global pull.ff only # Disallows non ff merges on pull. Overrides merge.ff when pulling
git config --global merge.ff false # even create extra merge commit when fast forward merge would be possible

Only loosely related I've also found this setting avoids trouble during pull

git config --global pull.rebase true # set up pull to rebase instead of merge
bastian
  • 880
  • 8
  • 20
-1

Well hey, it works, 10 years later :D

git config --merge.ff no