使用Git,如何记录两个特定分支之间的合并提交的所有提交?

时间:2014-02-05 15:29:44

标签: git git-merge git-log

假设我的Git存储库包含分支masterBranchABranchBBranchC

现在所有这些分支都已合并为主分支,可能多次(无论出于何种原因,这是一个假设情景)。我希望能够找到BranchA合并到master的所有合并提交。

在我提出这个问题之前,这是我所得到的:

git log master ^BranchA --merges --oneline

这让我获得了master而非BranchA的所有提交,这些提交也是合并提交。这实际上给了我正在寻找的所有提交,但它也可以给我提交我不想要的提交,例如从BranchBBranchC合并到master。

示例输出:

10bdc8b Merge branch 'BranchA'
383693a Merge branch 'BranchB'
8af3b5c Merge branch 'master' of 192.168.0.0:/path/to/repo.git
aa0f22c Merge branch 'master' into BranchC
72bbf3a Merge branch 'BranchA'
fac1157 Merge branch 'BranchB'

我想找到一个只输出10bdc8b72bbf3a的解决方案。而且不要仅仅为'BranchA'这个名字而烦恼;我知道在这种情况下可以使用,但总是可以为合并提交提供自定义消息,因此它可能并不总是有效。


修改

到目前为止反应良好,但不幸的是,我碰到了一堵我不知道如何过去的墙。请考虑以下情形:

   F                               <-BranchB
  / \        
 /   \        
A-----B----C-----D--E----K----L    <-master
       \        /    \       /
        \      /      \     /
         G----H--------I---J       <-BranchA

现在,我的目标是找到从BranchA到master的所有合并提交。通过查看图表,我可以看到我正在寻找LD。然而,阻止我以编程方式解决这个问题的曲线球是合并提交I,其中master被合并到BranchA中。

在这种情况下,如果我们在master中的所有提交中使用branch --contains方法,我们会得到LDB。但是,如果我们在master中的所有提交中而不是在BranchA中进行分支 - 包含,则我们只获得L。这两种方法都没有得到理想的输出。

同样,如果我们使用git merge-base查找父级,我们只会获得L

据我所知,似乎没有一种好方法可以将BD分开,因为这两个提交都在BranchA的历史中。我可以通过看他们说他们是不同的,但Git似乎没有一个很好的方法来区分他们。

2 个答案:

答案 0 :(得分:1)

git中没有单个命令可以从特定分支获取所有合并,但是您可以组合branch --contains并合并父项walk来关闭。忽略章鱼提交,在主分支上我们对第二个合并父代感兴趣:

bash$ for commit in \
        $(git log --format=%h --merges --max-parents=2 master ^topic); do \
          [[ $(git branch --contains ${commit}^2) =~ topic ]] && \
          echo $commit; done

当然,你必须确保没有合并快进,也就是说,你必须在合并时指定--no-ff开关,否则你将失去必要的双父分支。上面的scriplet依赖。

还有一个额外的考虑因素,是否是并发症取决于您的具体用例。在以下示例中,

I--A--M---N---O---F  ← master
 \   /       /   /
  `-B-------D ← / ← topicA
     \         /
      `--C----E ← topicB

提交B是合并提交M的父级,是ED的祖先。当您在master上查询合并提交时,您将收到提交F,O,M,然后当您查询哪些是topicA分支合并时,您将获得M,O但是您当你问其中哪一个是M分支合并时,也会得到topicB,这是因为B是两个分支的祖先。

答案 1 :(得分:0)

我认为在Git中没有直接的方法可以解决这个问题,但我知道如何解决这个问题。如果是我,我会用Python做这件事。其他人可能会在Bash中这样做。

首先,我将获得A中的合并提交列表以及他们合并的父母:

git log --merges --format="%H %P" A

我会迭代结果中的每一行,查看第三个哈希值(假设所有合并只有两个父项)。该行的第一个哈希是合并提交本身的哈希 - 如果这个合并结果是在A和B之间,那就是我们想要的答案。第二个哈希是A分支中的父。第三个哈希是另一个父,我们要测试其中B的成员资格。因此,对于每个(第三个)哈希,我会调用

git merge-base B <hash>

...如果结果与我输入的哈希相同,则该提交(该行的第一个哈希)是合并到分支B的分支A中。