我有一个带有master和a分支的存储库,在这两个分支之间有很多合并活动。当分支A基于master创建时,我如何在我的存储库中找到提交?

我的存储库基本上是这样的:

-- X -- A -- B -- C -- D -- F  (master) 
          \     /   \     /
           \   /     \   /
             G -- H -- I -- J  (branch A)

我正在寻找修订A,这不是git merge-base(——all)找到的。


当前回答

你可能正在寻找git merge-base:

Git merge-base找到两个提交之间的最佳共同祖先,用于三向合并。一个共同祖先优于另一个共同祖先,如果后者是前者的祖先。没有更好的公共祖先的公共祖先是最佳公共祖先,即合并基。注意,对于一对提交可以有多个合并基。

其他回答

问题似乎是在一边的两个分支之间找到最近的单次提交切割,在另一边找到最早的共同祖先(可能是回购的初始提交)。这符合我对“分支”点的直觉。

记住,使用普通的git shell命令来计算这一点并不容易,因为git rev-list——我们最强大的工具——不允许我们限制提交到达的路径。我们拥有的最接近的是git rev-list——boundary,它可以给我们一组“阻塞我们的方式”的所有提交。(注意:git rev-list——ancestry-path很有趣,但我不知道如何让它在这里有用。)

下面是脚本:https://gist.github.com/abortz/d464c88923c520b79e3d。它相对简单,但由于循环,它的复杂程度足以保证要点。

请注意,这里提出的大多数其他解决方案不可能在所有情况下都有效,原因很简单:git rev-list—first-parent在线性化历史时不可靠,因为两种顺序都可能存在合并。

另一方面,Git rev-list -topo-order非常有用——用于按地形顺序进行提交——但执行差分是很脆弱的:对于给定的图,有多种可能的地形顺序,因此您依赖于排序的某种稳定性。也就是说,strongk7的解决方案可能在大多数时候都非常有效。然而,它比我的慢,因为必须遍历整个回购历史…两次。: -)

你可能正在寻找git merge-base:

Git merge-base找到两个提交之间的最佳共同祖先,用于三向合并。一个共同祖先优于另一个共同祖先,如果后者是前者的祖先。没有更好的公共祖先的公共祖先是最佳公共祖先,即合并基。注意,对于一对提交可以有多个合并基。

我相信我已经找到了一种方法来处理这里提到的所有极端情况:

branch=branch_A
merge=$(git rev-list --min-parents=2 --grep="Merge.*$branch" --all | tail -1)
git merge-base $merge^1 $merge^2

查尔斯·贝利(Charles Bailey)非常正确,基于祖先顺序的解决方案价值有限;在一天结束的时候,你需要某种记录“这个提交来自分支X”,但这样的记录已经存在;默认情况下'git merge'会使用一个提交消息,例如“merge branch 'branch_A' into master”,这告诉你所有来自第二个父分支(commit^2)的提交都来自'branch_A',并合并到第一个父分支(commit^1),也就是'master'。

有了这些信息,你可以找到'branch_A'的第一次合并(这是'branch_A'真正存在的时候),并找到merge-base,这将是分支点:)

我尝试了Mark Booth和Charles Bailey的仓库,解决方案是有效的;怎么可能呢?唯一不可行的方法是手动更改合并的默认提交消息,从而真正丢失分支信息。

用途:

[alias]
    branch-point = !sh -c 'merge=$(git rev-list --min-parents=2 --grep="Merge.*$1" --all | tail -1) && git merge-base $merge^1 $merge^2'

然后你可以使用'git branch-point branch_A'

喜欢。)

我使用git rev-list来做这类事情。例如,(注意3个点)

$ git rev-list --boundary branch-a...master | grep "^-" | cut -c2-

将分叉点吐出来。这并不完美;因为你已经多次将master合并到分支A中,这将分离出两个可能的分支点(基本上,最初的分支点,然后是你将master合并到分支A的每个点)。然而,它至少应该缩小可能性。

我将该命令添加到~/中的别名中。gitconfig:

[alias]
    diverges = !sh -c 'git rev-list --boundary $1...$2 | grep "^-" | cut -c2-'

所以我可以称它为:

$ git diverges branch-a master

为什么不使用

git log master..enter_your_branch_here --oneline | tail -1

它提供了分支A拥有而master没有的所有提交(..的函数),并且tail -1返回输出的最后一行,这将为您找到指定分支(分支A)的第一次提交。

然后,使用那个提交的SHA

git log enter_the_sha_here^1 --oneline | head -1

它提供了指定提交(^1函数)之前的所有提交,并返回head -1输出的第一行,这是在分支A(又名“分支点”)最早提交之前的“一次提交”。


作为一个单独的可执行命令:

for COMMIT in $(git log --format=format:%H  master..HEAD | tail -1) ; do
    git log $COMMIT^1 --oneline | head -1
done

在分支A (HEAD的功能)中运行上述操作