如何判断一个提交是否是另一个提交的祖先(反之亦然)?

时间:2013-08-20 21:20:42

标签: git git-history-graph

Git是DAG个快照,图中的每个节点都代表一个提交。每个提交都可以有'n'个父提交。

鉴于任何两次提交,是否有一种简洁的方法来识别DAG中这两者的“顺序”。 git rev-list似乎是最有希望的,但我似乎无法找到正确的咒语。

理想情况下,我会有以下内容

$ git related hash1 hash2
hash1 is ancestor of hash2

OR

hash2 is ancestor of hash1

OR

hash1 unrelated to hash2

OR

hash1 is equal to hash2

5 个答案:

答案 0 :(得分:59)

使用git merge-base --is-ancestor <commit1> <commit2>

找到答案的方法不止一种。最简单的是使用

git merge-base --is-ancestor <commit> <commit>

来自git merge-base的文档:

--is-ancestor
     

检查第一个<commit>是否是第二个<commit>的祖先,如果为真,则退出状态为0,否则退出状态为1。错误由非零状态发出信号,该状态不是1.

其他选项

带有三点...符号的git log

另一种选择是使用git log并使用三点符号...告诉Git输出子提交的集合并减去集合交集。基本上,它告诉你一组提交如何相互分离:

$ git log --oneline --graph --left-right \
--first-parent --decorate <commit1>...<commit2>

上面的命令将显示从commit1commit2可以访问的提交,但不能同时显示两者,即C1 UNION C2 - C1 INTERSECTION C2,就设置操作而言。

如果提交都不是另一方的父级,那么您将看到两者的子提交,但如果一方是另一方的祖先,那么您只会看到后代提交的输出,因为祖先包含在后代的路径中,因此被排除在输出之外。

您可以从以下资源中了解有关git log和三点符号的更多信息:

  1. git-log(1)
  2. gitrevisions(1): Specifying Ranges
  3. Revision Selection
  4. git branch --contains选项

    git-rev-list(1)似乎可以用它来回答这个问题。另一种方法是简单地将临时分支标签附加到您要测试的提交,然后使用git branch--contains选项:

    git branch --contains <commit-to-test>
    

    输出将是在其提交树中某处包含提交的所有分支,因此通过在另一个提交上使用临时分支,您可以查看您正在测试的提交是否是祖先。

    来自文档:

    --contains [<commit>]
    
         

    仅列出包含指定提交的分支(如果未指定,则为HEAD)。

答案 1 :(得分:7)

以下shell脚本可能会起到作用:

if git rev-list $SHA1 | grep -q $SHA2 ; then echo "$SHA2 is ancestor of $SHA1"
elif git rev-list $SHA2 | grep -q $SHA1 ; then echo "$SHA1 is ancestor of $SHA2"
else echo "$SHA1 unrelated to $SHA2" ; fi

或者,将它整齐地包装成一个git别名:

git config --global alias.related '!function git_related() { if git rev-list $1 | grep -q $2 ; then echo "$2 is ancestor of $1" ; elif git rev-list $2 | grep -q $1 ; then echo "$1 is ancestor of $2" ; else echo "$1 unrelated to $2" ; fi } ; git_related $1 $2'

答案 2 :(得分:2)

if   (( $(git rev-list $1..$2|wc -l) == 0 )); then echo "$2 is ancestor of $1"
elif (( $(git rev-list $2..$1|wc -l) == 0 )); then echo "$1 is ancestor of $2"
else echo "$1 and $2 are unrelated"
fi

答案 3 :(得分:1)

git log  --oneline -1  OLD_SHA..NEW_SHA

如果这给你一些日志,那么OLD_SHA是NEW_SHA的父母。

答案 4 :(得分:0)

要构建@helmbert的优秀git related别名,这里的版本也接受分支名称(或HEAD等)作为参数,而不仅仅是提交ID:

git config --global alias.related '!function git_related() { commit1=`git log -n 1 --format="%h" $1` ; commit2=`git log -n 1 --format="%h" $2` ; if git rev-list $commit1 | grep -q $commit2 ; then echo "$2 is ancestor of $1" ; elif git rev-list $commit2 | grep -q $commit1 ; then echo "$1 is ancestor of $2" ; else echo "$1 unrelated to $2" ; fi } ; git_related $1 $2'