Can I make fast forwarding be off by default in Git?
Asked Answered
C

5

300

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.

Chronometry answered 23/3, 2010 at 13:38 Comment(10)
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?Margretmargreta
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. :-)Chronometry
Turning off fast forwarding is extremely useful, particularly when following a model like A successful Git branching modelCloakanddagger
Please change the accepted answer for this to Eric Platon's answer https://mcmap.net/q/65893/-can-i-make-fast-forwarding-be-off-by-default-in-git - 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.Interbedded
@Steiny No, it just makes your repository a mess: endoflineblog.com/gitflow-considered-harmful.Broeker
@Broeker 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.Cloakanddagger
@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.)Broeker
@Broeker You are making claims that are very strong and biased, you literally said "No, it just makes your repository a mess" regarding this article nvie.com/posts/a-successful-git-branching-model, while this Git workflow might not work for you, it works for some enterprise teamsDarendaresay
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"?Lhasa
I think the comments (and the referenced blog post) about the way a non-fast-forward merge "makes your repository a mess" are missing the point. That "mess" is not the result of a complicated merge structure — it's the result of the lack of good tools for visualizing a complicated merge structure. A fast-forward merge "removes" the mess — but in doing so, it erases history, creating a sanitized version which can, yes, be more easily viewed using a meager one-dimensional log viewer.Criticism
D
304

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.

Discreditable answered 23/3, 2010 at 13:58 Comment(17)
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.Discreditable
Does this affect "git pull" and its merge strategy at all?Rear
@Thomas: Yes; git pull is git fetch + git merge.Sunroom
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?Oversew
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.Hargrove
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 inceptionBlackmarketeer
Beware of --no-ff - it can break blame and disectLittlest
What if I'm just tired of typing git merge --no-ff (branchname)? And I want git pull to function as it always has?Unbearable
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.Ancestor
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 trueInterbedded
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.<branchName>.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.Endosmosis
@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"Nephograph
Since Git 2.4.3 you can specify pull.ff (to true) config options to override mergeOptions for pull command.Ize
FYI: This is just for the master branch, if you want for all branches you need @eric-platon's answerCalvillo
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.Omentum
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://mcmap.net/q/65893/-can-i-make-fast-forwarding-be-off-by-default-in-git] answer as correct. By doing what he says, pull stays the same.Issacissachar
Not sure how to ask a sort of sub-question ... but I don't seem to have any options related to NOT fast forwarding on a merge ... but that's what happens. I merge a branch from origin and I get a merge commit (actually what is wanted in our situation). Does local vs origin merging make a difference?Mandel
I
377

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).

Irreverent answered 25/7, 2011 at 0:21 Comment(10)
Note: merge.ff was introduced in Git 1.7.6. It is not effective in older versions.Synecious
For people using Git 1.7.6, this is the best and simplest solution.Ancestor
I'm using this together with an alias puff = "pull --ff --ff-only"Endodermis
I really like the alias option, since your pulls won't result in a merge commit always.Flown
Theres is also (now, see git-scm.com/docs/git-config) the option pull.ff which can be set to only, which will do the same as the alias.Webworm
Thank you, @jotomo. That feature is available from Git v2.0.0 (from commit b814da891e8261b909fc5d9fb07b4e8b13989c2d).Irreverent
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.Interbedded
Is there a way to only make this apply when merging branches and not when doing a git pull?Herald
For it to work on our systems i needed git config --global --bool merge.ff false (git version 2.20.1)Bord
Be careful with the flag --add.Rosel
D
304

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.

Discreditable answered 23/3, 2010 at 13:58 Comment(17)
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.Discreditable
Does this affect "git pull" and its merge strategy at all?Rear
@Thomas: Yes; git pull is git fetch + git merge.Sunroom
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?Oversew
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.Hargrove
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 inceptionBlackmarketeer
Beware of --no-ff - it can break blame and disectLittlest
What if I'm just tired of typing git merge --no-ff (branchname)? And I want git pull to function as it always has?Unbearable
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.Ancestor
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 trueInterbedded
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.<branchName>.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.Endosmosis
@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"Nephograph
Since Git 2.4.3 you can specify pull.ff (to true) config options to override mergeOptions for pull command.Ize
FYI: This is just for the master branch, if you want for all branches you need @eric-platon's answerCalvillo
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.Omentum
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://mcmap.net/q/65893/-can-i-make-fast-forwarding-be-off-by-default-in-git] answer as correct. By doing what he says, pull stays the same.Issacissachar
Not sure how to ask a sort of sub-question ... but I don't seem to have any options related to NOT fast forwarding on a merge ... but that's what happens. I merge a branch from origin and I get a merge commit (actually what is wanted in our situation). Does local vs origin merging make a difference?Mandel
R
31

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

# Disallows non ff merges on pull. Overrides merge.ff when pulling
git config --global pull.ff only

# Even create extra merge commit when fast forward merge would be possible
git config --global merge.ff false

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

# Set up pull to rebase instead of merge
git config --global pull.rebase true
Rincon answered 23/1, 2018 at 18:19 Comment(3)
git config --global pull.rebase true # notice 'true' at the end of the lineKerriekerrigan
Thanks @Kerriekerrigan I've fixed thisRincon
Yes! The top-ranked answer misses this. Also, Git Common Flow, arguably the de-facto standard, says, "It is RECOMMENDED that all branches be merged using git merge --no-ff " but when you're pulling, merge has already happened, so this seems the like best answer in 2021--at least to me.Cobbie
A
2
git config --replace-all pull.ff false

The above command worked for me to remove fast forward merge from all branches

Archfiend answered 29/8, 2023 at 9:20 Comment(0)
W
0

These answers didn't work for me until I applied the config not only on global:

git config --global pull.ff only
git config pull.ff only

in local my pull.ff config was false (instead of only)

Wald answered 30/11, 2022 at 14:49 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.