摘要:git merge-base --is-ancestor
测试一个提交是否是另一个提交的祖先(提交被认为是他们自己的祖先,这是一种特别奇怪的乱伦形式,也许:-))。由于分支标签只能git merge
在当前分支 ( HEAD
) 指向作为另一个提交的祖先的提交时才可以快进,因此我们可以使用它来确定是否git merge
可以进行快进操作。
看起来您希望将其发布为答案,因此我已将其转换为有效的 git 别名,您可以将其放入全局 git 配置中。别名有点长且复杂,最好将其剪切并粘贴到您的 git config 别名部分:
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"
这是用 shell 脚本编写的相同内容,以更易读的方式和一些评论:
#! /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
}
f
shell 脚本只需要一个主要部分来驱动它,它是别名之后的调用。别名本身只是将所有内容从一行中铲入canff
并upstream_name
放入一行。然后 Git 的配置文件规则要求整个别名用双引号引起来,这反过来又要求将所有内部双引号转换为反斜杠双引号序列。
(我还删除了该local b
语句,因为作为别名,这每次都会启动一个新的 shell 实例,因此变量名的卫生变得不重要。)
(实际上可以将别名写成多行。只需在每个换行符前加上反斜杠即可。但是,这个别名太复杂了,这样看起来也很难看,所以我最终只留下了一大行。)