Git:查找两个分支最近的共同祖先

1157

如何找到两个Git分支的最近公共祖先?


3
最近一次是指实际时间、提交数量或其他度量标准? - Ciro Santilli OurBigBook.com
2
相关的(交叉合并):https://dev59.com/HYTba4cB1Zd3GeqP30YU - jub0bs
@YakovL 我认为不行,因为分支和你可以在提交对象上设置任意提交日期:那个日期本身可能不是你想要的。 - Ciro Santilli OurBigBook.com
2
@CiroSantilli新疆改造中心996ICU六四事件 在我看来,只有在树中最后一个公共提交之前存在一个具有较早时间戳的提交,才可能出现不同。你能提供一个不那么琐碎的例子吗? - YakovL
6个回答

1449

您需要使用git merge-base。用法:

$ git merge-base branch2 branch3
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2

116
请注意,这会找到最近的共同祖先...我相信这就是提问者想要的,所以给它加上一分。只是想提醒一下,如果有人来这里寻找最老的共同祖先(就像我一样),也可以参考:https://dev59.com/LHI_5IYBdhLWcg3wF_F3 - lindes
23
@funroll:或者简写为:git log master...HEAD。 翻译:@funroll提到,也可以使用简写方式git log master...HEAD来实现相同的功能。 - CB Bailey
29
最古老的共同祖先不是最初的提交吗? - Thorbjørn Ravn Andersen
11
@ThorbjørnRavnAndersen,是的,我想那是这样的... 描述上的困难在于git使用有向无环图,但通常被认为是树, 但从技术上讲它不是树。为了更加谨慎地措辞,我在谈论当您想要第一个“分支”实例的父节点时......由于可能存在多个重新合并和拆分的点,因此这是这些中“最古老”的,但不是真正的最古老的祖先,这应该始终是初始提交(我想)。 - lindes
17
虽然这个问题严格来说是关于找到两个分支的共同祖先,但任何想要找到三个或更多分支的共同祖先的人应该注意需要传递--octopus标志才能获得正确的结果。显而易见但是错误的 git merge-base branch1 branch2 branch3会给出一个提交记录,但是根据文档中的讨论部分所描述的,这个提交不一定是所有三个分支的共同祖先。 - Mark Amery
显示剩余3条评论

77

git diff master...feature

显示当前(可能包含多个提交)功能分支的所有新提交。

man git-diff 文档中说明:

git diff A...B

与之相同:

git diff $(git merge-base A B) B

但是 ... 更容易输入和记忆。

Dave所提到的,HEAD 这种特殊情况可以省略。因此:

git diff master...HEAD

与这个相同:

git diff master...

如果当前分支是feature,那么这就足够了。

最后,请记住顺序很重要!执行git diff feature...master将显示在master而不在feature上的更改。

我希望更多的git命令支持这种语法,但我认为它们没有。有些甚至对于...有不同的语义:Git提交范围中双点“..”和三点“…”之间有什么区别?


9
或者在特殊情况下,如果要与“HEAD”进行比较,则只需使用“git diff master...”。 - Dave
“...”在PowerShell中对我无效,有趣的是它在Git控制台中有效,也许仓库不完整,但是git diff $(git merge-base A B) B有效,由于我对Git还比较新,所以我有点怀疑这是否会合并分支 :) - Moiz Ahmed
1
哇,非常惊人。如果你的本地仓库中不存在你想要的分支,因为你从未检出过它,你可以简单地执行 git diff origin/branchname... - Mark Ch
2
那么 git diff branchA..branchBgit diff branchA...branchB 有什么区别呢? - Bharat Pahalwani
@BharatPahalwani,在阅读了您的评论后,我在谷歌上搜索发现这个链接是第三个。https://matthew-brett.github.io/pydagogue/git_diff_dots.html 在您发表评论之前,您尝试过什么? - ssi-anik

52

如之前的回答所述,尽管git merge-base可行,

$ git merge-base myfeature develop
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2

如果myfeature是当前分支,这很常见,你可以使用--fork-point


$ git merge-base --fork-point develop
050dc022f3a65bdc78d97e2b1ac9b595a924c3f2

这个参数仅适用于足够新版本的Git。不幸的是,它并不总是有效,而且目前并不清楚原因。请参考此答案末尾所述的限制。


如需完整的提交信息,请考虑:

$ git log -1 $(git merge-base --fork-point develop) 

2
我有 git version 2.14.1.windows.1。使用一个分支(带有自己的提交)运行 git merge-base --fork-point branch2,而我知道该分支已经从当前分支分叉,但是没有任何结果,然而 git merge-base branch1 branch2 正确显示了分叉点。可能出了什么问题? - ADTC
@ADTC 请检出 branch2,然后运行 git merge-base --fork-point branch1 - Asclepius
我在图形化视图中查看树状结构时,并没有发现任何异常。我可以追踪路径并找到与 git merge-base branch1 branch2 结果匹配的共同祖先。但奇怪的是,--fork-point 无论如何都没有给出任何结果。你确认它对你有用吗? - ADTC
@ADTC,我现在在Linux上尝试了git 2.14.1,对我来说它很好用。我不知道该告诉你什么。 - Asclepius
1
我得到了与@ADTC相同的结果。在使用git版本2.16.2.windows.1时,命令“git log -1 $(git merge-base --fork-point anotherBranch)”没有显示任何结果。 - masinger
显示剩余5条评论

14

使用 gitk 可以以图形方式查看两个分支:

gitk branch1 branch2

然后就容易在这两个分支的历史记录中找到共同祖先。


12
并非所有情况下都可以通过视觉实现所有事情。有时需要通过编程自动化来完成任务,这是有原因的。 - ADTC
3
并非每个答案都必须覆盖所有可能情况才有用。 - Martin G
3
我为我的过去道歉。我不记得当时为什么写了那个。 - ADTC

0

找到所有分支的共同祖先

git merge-base $(git branch --format "%(refname)")

-1
git checkout myRep
git pull origin main --allow-unrelated-histories
git push origin myRep

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接