Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve `git --no-ff --ff-only` which is not allowed

Tags:

As part our rebase-heavy workflow, I am hoping to use a merge on the master branch. In particular I want to merge only when the topic branch has been rebased onto the most recent master commit thereby making any merge a fast-forward one. I can achieve that by using:

git merge --ff-only

Furthermore, I would like to record the integration of the topic branch with an empty commit which is why I would like to use --no-ff which forces that behaviour:

git merge --no-ff

What I really want, though, is a combination of both: merge only when it's trivial but let me record it anyway. Git thinks that

fatal: You cannot combine --no-ff with --ff-only.

which appears self-evident to some.

git merge --edit --no-ff topicbranch

doesn't achieve the behaviour I want either. So how can I merge with the --no-ff option iff the topic branch in question is rebased to the latest master commit?


UPDATE: Seems like Charles Bailey's answer will do the trick. If you desire to have this rolled into a git alias you could issue this here:

git config --global alias.integrate '!test "$(git merge-base HEAD "$1")" = "$(git rev-parse HEAD)" && git merge --no-ff --edit $1 || echo >&2 "Not up-to-date; refusing to merge, rebase first!"' 

A bit of a mouthful but works. Note the force of a commit message edit with option --edit.

like image 449
DrSAR Avatar asked Mar 26 '13 07:03

DrSAR


2 Answers

You don't want --ff-only because you do want to make a merge commit which --ff-only would inhibit.

The check that you want can be made as a separate check before running the merge command. You could package this into a simple shell function.

E.g.

merge_if_ahead () {   if test "$(git merge-base HEAD "$1")" = "$(git rev-parse HEAD)"; then       git merge --no-ff "$1"   else       echo >&2 "Not up to date; refusing to merge"       return 1   fi } 
like image 60
CB Bailey Avatar answered Oct 06 '22 03:10

CB Bailey


I've created an alias that works for my simple tests

git config --global alias.ffmerge '!sh -c "git merge --ff-only $1 && git reset --hard HEAD@{1} && git merge --no-ff $1" -' 

It consists of 3 commands, one after each other, that will fail as soon as the first one fails. Explaining each:

git merge --ff-only $1 

Will fail if the merge cannot continue as a fast-forward merge. ($1 is the branch name passed in as argument)

git reset --hard HEAD@{1} 

If the first command succeeds it means we can do a fast-forward merge but as we want to do a merge commit we'll move back to the state of HEAD just before our (successful) merge. HEAD@{1} is a reflog pointer.

git merge --no-ff $1 

Now we'll do the real merge with a merge commit even if the merge can go a head as a fast-forward.

A simple call to git ffmerge will do the entire thing for us, the only step that can fail is the first and that would leave us in an unchanged working copy as before.

As always with git reset --hard the working copy should be clean.

like image 29
Andreas Wederbrand Avatar answered Oct 06 '22 01:10

Andreas Wederbrand