Determine if merging will be resolved using fast forward

I want to know if a particular merge will be resolved using fast forward or not before running the merge command.

I know that I can specifically request a merge so that it is not allowed using fast forward (using the --no-ff option). Or that I can try to allow merging only by fast-forwarding (using the --ff option).

But sometimes I want to know if a particular merge will be resolved with fast forward before starting it. I understand that I can theoretically work it out by making my way through the tree of history. And I also understand that I can start the merge and see what happens, but it becomes problematic if I then decide that I would prefer the merge to be resolved in a different way, since I have to cancel the merge (by repeating branch tags in ref -log) and do it again.

NOTE. The question --dry-run ( Is there a git -merge -dry-run option? ) Is much more concerned with which merge conflicts can exist in a merge, and not about merges that can be resolved by fast forward.

+6
source share
4 answers

Summary: git merge-base --is-ancestor checks if one commitment is the ancestor of another (where commits are considered their own ancestors, which is a particularly strange form of incest, perhaps :-)). Since the branch label can only be redirected using git merge , when the current branch ( HEAD ) indicates a commit that is the ancestor of another commit, we can use this to determine if git merge quickly execute -forward.

It sounds like you wanted this to be posted as an answer, so I converted it to a working git alias that you can add to your global git configuration. The alias is a bit long and complex, and it's probably best to just cut and paste it into your git aliases section:

 canff = "!f() { if [ $# -gt 0 ]; then b=\"$1\"; git rev-parse -q --verify \"$b^{commit}\" >/dev/null || { printf \"%s: not a valid commit specifier\n\" \"$b\"; return 1; } else b=$(git rev-parse --symbolic-full-name --abbrev-ref @{u}) || return $?; fi; if git merge-base --is-ancestor HEAD \"$b\"; then echo \"merge with $b can fast-forward\"; else echo \"merge with $b cannot fast-forward\"; fi; }; f" 

Here is the same thing that is written as a shell script, in a more readable way and some comments:

 #! /bin/sh # # canff - test whether it is possible to fast-forward to # a given commit (which may be a branch name). If given # no arguments, find the upstream of the current (HEAD) branch. # First, define a small function to print the upstream name # of the current branch. If no upstream is set, this prints a # message to stderr and returns with failure (nonzero). upstream_name() { git rev-parse --symbolic-full-name --abbrev-ref @{u} } # Now define a function to detect fast-forward-ability. canff() { local b # branch name or commit ID if [ $# -gt 0 ]; then # at least 1 argument given b="$1" # make sure it is or can be converted to a commit ID. git rev-parse -q --verify "$b^{commit}" >/dev/null || { printf "%s: not a valid commit specifier\n" "$b" return 1 } else # no arguments: find upstream, or bail out b=$(upstream_name) || return $? fi # now test whether git merge --ff-only could succeed on $b if git merge-base --is-ancestor HEAD "$b"; then echo "merge with $b can fast-forward" else echo "merge with $b cannot fast-forward" fi } 

The shell script just needs the main section to drive it, which is the f call after the alias. The alias itself simply dug up everything: from canff and upstream_name to one line. The git configuration file rules require that the entire alias be enclosed in double quotes, which in turn requires that all internal double quotes be converted to double-backslash sequences.

(I also pulled out the local b statement, because as an alias, it starts a new shell instance each time, so hygiene of the name variable becomes unimportant.)

(In fact, you can write an alias as multiple lines. Just a prefix for each new line with a backslash. However, this alias is so complex that it looks too ugly, so I ended up leaving only one large line.)

+3
source

You can check if git merge-base <branch1> <branch2> git rev-parse <branch1> . If the value is equal, ff merge or is already updated when git merge <branch1> <branch2> . If not, merge non-ff.

 function isff(){ a=$(git merge-base $1 $2) b=$(git rev-parse $1) c=$(git rev-parse $2) if [[ "$b" == "$c" ]] || [[ "$a" == "$c" ]];then echo merge dry run: already up-to-date return fi if [ "$a" == "$b" ];then echo merge dry run: a fast forward merge else echo merge dry run: a non fast forward merge fi } 

isff master topic

+1
source

There is a similar, but not quite the same question: Is there a git -merge -dry-run option?

The first answer looks like it might be what you are looking for.

In particular, a merge with the --no-commit flag and using --abort if you have seen enough and want to go back and do the actual merge.

0
source

Looking at the question @ Ashwin-nair refers to, I found what, in my opinion, is the answer.

For

 git checkout MY_BRANCH git merge OTHER_BRANCH 

If the conclusion

 git branch --contains MY_BRANCH 

contains OTHER_BRANCH , merging with OTHER_BRANCH can be enabled using fast forward.

0
source

All Articles