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

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

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

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


当前回答

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

记住,使用普通的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 rev-list branch...master

你得到的最后一行是分支上的第一个提交,所以接下来的问题是获取它的父节点。所以

git rev-list -1 `git rev-list branch...master | tail -1`^

似乎为我工作,不需要差异等(这是有帮助的,因为我们没有那个版本的差异)

更正:如果你在主分支上,这是行不通的,但我在一个脚本中这样做,所以这不是一个问题

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

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'

喜欢。)

你可以使用下面的命令返回branch_a中最老的提交,master无法访问它:

git rev-list branch_a ^master | tail -1

也许有一个额外的健全性检查,该提交的父节点实际上可以从master访问…

经过大量的研究和讨论,很明显没有什么灵丹妙药能在所有情况下都起作用,至少在当前版本的Git中不是这样。

这就是为什么我写了几个补丁,增加了尾巴分支的概念。每次创建分支时,也会创建一个指向原始点的指针,即tail ref。每当分支重基时,这个ref都会更新。

要找到devel分支的分支点,你所要做的就是使用develop @{tail},就是这样。

https://github.com/felipec/git/commits/fc/tail

当然我遗漏了一些东西,但在我看来,以上所有的问题都是因为我们总是试图找到历史上的分支点,这导致了各种各样的问题,因为可用的合并组合。

相反,我采用了一种不同的方法,基于两个分支共享很多历史,分支之前的所有历史都是100%相同的,所以我的建议是向前(从第一次提交开始),寻找两个分支的第一个差异。简单地说,分支点就是找到的第一个差值的父点。

在实践中:

#!/bin/bash
diff <( git rev-list "${1:-master}" --reverse --topo-order ) \
     <( git rev-list "${2:-HEAD}" --reverse --topo-order) \
--unified=1 | sed -ne 's/^ //p' | head -1

它解决了我所有的常规案件。当然,有些边境地区没有被覆盖,但是…你好:-)