12

我想知道在运行合并命令之前特定的合并是否会通过“快进”解决。

我知道我可以明确要求不通过“快进”(使用--no-ff选项)解决合并。或者我可以尝试仅通过快进(使用--ff选项)来解决合并问题。

但有时我想知道某个特定的合并是否会在我运行它之前通过快进解决。我意识到理论上我可以通过挖掘历史树来解决这个问题。而且我也意识到我可以运行合并并查看会发生什么,但是如果我决定我希望以另一种方式解决合并,这将成为问题,因为我必须撤消合并(通过重新指向分支标签在参考日志中),然后再做一次。

注意:--dry-run问题(Is there a git-merge --dry-run option?)更多的是关于查看合并中可能存在的合并冲突,而不是关于可以通过快进解决的合并。

4

4 回答 4

11

摘要: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
}

fshell 脚本只需要一个主要部分来驱动它,它是别名之后的调用。别名本身只是将所有内容从一行中铲入canffupstream_name放入一行。然后 Git 的配置文件规则要求整个别名用双引号引起来,这反过来又要求将所有内部双引号转换为反斜杠双引号序列。

(我还删除了该local b语句,因为作为别名,这每次都会启动一个新的 shell 实例,因此变量名的卫生变得不重要。)

(实际上可以将别名写成多行。只需在每个换行符前加上反斜杠即可。但是,这个别名太复杂了,这样看起来也很难看,所以我最终只留下了一大行。)

于 2016-06-08T22:55:27.313 回答
1

您可以测试是否git merge-base <branch1> <branch2>等于git rev-parse <branch1>。如果相等,则 ff 合并或在您运行时已经是最新的git merge <branch1> <branch2>. 如果不是,则为非 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

于 2016-06-06T03:25:44.327 回答
0

查看@Ashwin-nair 引用的问题,我找到了我认为的答案。

为了

git checkout MY_BRANCH 
git merge OTHER_BRANCH 

如果输出

git branch --contains MY_BRANCH

contains ,然后可以通过快进解决OTHER_BRANCH合并。OTHER_BRANCH

于 2016-06-06T03:30:37.870 回答
0

这里有一个类似但不完全相同的问题:Is there a git-merge --dry-run option?

第一个答案看起来可能是您正在寻找的。

具体来说,当您已经看到足够的内容并想要返回并进行实际合并时,merge使用--no-commit标志和使用。--abort

于 2016-06-06T02:53:15.453 回答