如何判断一个提交是否是另一个提交的后代?


Answers:


51

如果要以编程方式(例如,在脚本中)检查此内容,则可以检查是否git merge-base A B等于git rev-parse --verify A(那么A可以从B到达),或者是否等于git rev-parse --verify B(那么B可以从A到达)。 git rev-parse需要从提交名称转换为提交SHA-1 /提交ID。

git rev-listVonC中使用like 回答也是可能的。

编辑:在现代Git中,该查询以的形式明确支持git merge-base --is-ancestor


如果你问提交的一个约是一个分支的顶端,然后git branch --contains <commit>或者git branch --merged <commit>可能是更好的非编程解决方案。


1
可能是最快的方法是git checkout -b quickcheck <more-recent-commit-ID>,然后git branch --contains <older-commit-ID>(然后git branch -D quickcheck摆脱临时党支部的)。
clee 2010年

2
两种可能的方法,它们都比@MattR答案中的一种差。
jwg

6
@jwg:MattR答案更好,但是这个答案(可能已经被接受)比git 1.8.0早git merge-base --is-ancestor2年。
JakubNarębski16年

@JakubNarębski很公平,对不起。
jwg

2
在一个大型存储库(200万次提交)中,我比较了git branch --contains <commit>和的速度git merge-base --is-ancestor ...:3m40s与0.14s
hagello

259

从Git 1.8.0开始,作为以下选项的支持merge-base

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

从手册页:

-是祖先

检查第一个是否是第二个的祖先,如果为true,则以状态0退出;否则,则以状态1退出。错误由非零的非1状态表示。

例如:

git merge-base --is-ancestor origin/master master; echo $?

4
真好!这是一个shell脚本,它将这个答案包装在具有人类可接收的输出的内容中:gist.github.com/simonwhitaker/6354592
Simon Whitaker

1
换句话说:git merge-base THING --is-ancestor OF_THING && echo yes || echo no例如:git merge-base my-feature-branch --is-ancestor master && echo yes || echo no
user1735594 '18

2
@smarber git merge-base --is-ancestor -- commit commit在我身边用git2.1.4(Debian / Devuan 7.10 jessie)和1.9.1(Ubuntu 14.04值得信赖)工作,它们现在已经很古老了。如果您愿意的话,它甚至对于Debian Wheezy也有效sudo apt-get install git/wheezy-backports
蒂诺

15

这种操作依赖于SO问题中详细介绍的修订范围的概念:“ 'git log origin / master'与'git log origin / master ..'之间的差异 ”。

git rev-list 应该能够从一次提交退回,直到可以到达为止。

所以我会尝试:

git rev-list --boundary 85e54e2408..0815fcf18a
0815fcf18a19441c1c26fc3495c4047cf59a06b9
8a1658147a460a0230fb1990f0bc61130ab624b2
-85e54e240836e6efb46978e4a1780f0b45516b20

(边界提交的前缀为-

如果显示的最后一个提交与git rev-list命令中的第一个提交相同,则它是从第二个提交可到达的提交。

如果第一次提交与第二次提交不可达,则不git rev-list返回任何内容。

git rev-list --boundary A..B

A如果A可以到达的话,将会结束B
它与:

git rev-list --boundary B --not A

B一个正参考,和A一个负参考
它将从开始B并在图形中返回,直到遇到可从到达的修订A
我认为,如果A可以直接从到达B,它将遇到(并且由于--boundary选择而显示)A本身。


这听起来像一个普通的用例,令我惊讶的是git尚未发布完全做到这一点的“瓷器”命令。
劳伦斯·西登

1
@lsiden:是的。旁注:不要忘记以编程方式检查某些内容,因此不应该使用瓷器命令(如stackoverflow.com/questions/6976473/…),而要使用管道命令(如stackoverflow.com/questions中所示)/ 3878624 /…
VonC

哦,伙计,看来我必须回去继续处理Shell脚本排骨了!
劳伦斯·西恩

1
问题:为什么-85e54e2...片段中的负号?还有一个可能的错字:“ ...与第一次提交...相同”
sdaau

1
@sdaau -表示这是边界提交。我已经对答案进行了编辑,以使其更清晰,以及刷新文档链接并修复这个已有5年历史的答案的错字。
VonC 2015年

11

另一种方法是使用git loggrep

git log --pretty=format:%H abc123 | grep def456

如果提交def456是提交abc123的祖先,则将产生一行输出,否则将不输出。

通常可以省略该--pretty参数,但是如果要确保只搜索实际的提交哈希而不搜索日志注释等,则需要这样做。


我以为这个解决方案会很慢,但实际上甚至是非常快,即使对于提交
超过

2
而不是--pretty我使用--oneline:git log --oneline ce2ee3d | grep ec219cc效果很好
gens


1

git show-branch branch-sha1 commit-sha1

哪里:

  • branch-sha1:要检查的分支中的sha1
  • commit-sha1:要检查的提交的sha1

0

如果您正在使用 git merge-base --is-ancestor,请确保使用Git 2.28(2020年第三季度)

在Git 2.28(2020年第三季度)中,“struct commit ”中并非总是存在已移至提交楼板。

请参阅Abhishek Kumar()的提交c752ad0提交c49c82a提交4844812提交6da43d9(2020年6月17日(通过合并JUNIOÇ滨野- -提交d80bea4,2020年7月6日)abhishekkumar2718
gitster

commit-graph:介绍 commit_graph_data_slab

签字人:Abhishek Kumar

在许多情况下都使用struct commit。但是,成员generationgraph_pos仅用于与提交图相关的操作,否则会浪费内存。

当我们过渡到第v2代时,这种浪费会更加明显,而第2代使用64位的代号而不是当前的32位。

由于经常commit_graph_data将它们一起访问,因此让我们介绍struct 并将其移至commit_graph_data平板。

尽管整个测试套件的运行速度与一样快master(系列:26m48s,master:27m34s,速度提高了2.87%),但是某些命令(如SzederGábor所发现的git merge-base --is-ancestor速度却降低了40%)。 最小化提交面板访问后,速度降低仍然存在,但接近20%。

Derrick Stolee认为,速度下降的原因是底层算法,而不是提交板访问速度慢,我们将在以后的系列文章中进行跟踪。


-1

如果您需要对存储库中的所有标签执行此操作,请建立在itub的答案上:

for i in `git tag` ; do echo -ne $i "\t" ; git log --pretty=format:%H $i | (grep <commit to find> || echo ""); done
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.