最初显示在分支上进行的提交(过滤掉合并的提交)

时间:2015-01-12 11:00:14

标签: git filter merge

在一个包含多个分支的git仓库中,我已将一个功能分支合并到主分支中,并从主分支合并到功能分支中。 我现在如何使用git log只查看在功能分支上进行的提交?我需要过滤掉对其他分支发出的评论,即使它们已被合并回这个功能分支。

$ git status
On branch some_feature

$ git checkout master
$ git merge some_feature
$ git checkout some_feature
$ git merge master

$ # Lots of coding and days gone by

$ git log --some_magic_here

如果重要,我想要运行git log的机器与用于编码该功能的机器不同。我需要此功能才能对其他开发人员的工作执行代码审核。在审核一个特定功能分支时,按author=SomeDev过滤并没有帮助。

1 个答案:

答案 0 :(得分:4)

TL; DR:您想要--first-parent(请参阅git rev-list documentation)和其他一些选择标准。

Git没有跟踪"实际提交了哪个分支"。例如,假设您在分支B上并执行此操作:

$ git checkout --detach B
[message about "detached head"]
[edit some file here, and git add result]
$ git commit -m message
$ git branch -f B HEAD
$ git checkout B

这将向分支B的提示添加新提交,即使提交是在不在分支上的时候进行的。或者,假设有两个分支B1B2都指向提交C7

... <- C5 <- C6 <- C7   <-- B1, B2

如果您的父项为C8的新提交C7,则将分支B2指向C8,该提交现在位于分支B2上。如果您在分支B1上进行了新提交,那么B1也会指向C8,但如果您然后使用git reset移动B1指向C7,无法再告诉 1 提交最初是在B1而不是B2进行的。

所有这一切,如果你在合并分支时保持良好的一致性,你可以在提交图上执行图遍历,找到提交&#34;之间的#34;特定的合并,然后通过一个特定的父链,来检测提交可能完成的提交。例如,如上所述featuremaster,假设始终在feature上进行提交,然后feature会定期合并到master --no-ff这样可以确保master上的每个合并提交都是真正的合并提交,而不仅仅是快进。然后图形模式将如下所示:

... --X--*------*-o---o-----*--*   <-- master
       \       /   \       /  /
        A--B--C--D--E--F--G--H     <-- feature

(其中&#34;时间&#34;随着向右移动而增加,*节点是在分支master上进行的合并提交,其中o个节点代表其他提交在主人身上。)

在这种情况下,您可以通过从feature(提交feature)的提示开始并且仅遍历第一个父提交来查找(可能)在H上进行的提交 - 这些是AH - 然后通过仅master上的第一次父提交来丢弃可查找的提交。第二个标准消除了上面标记为X的提交(以及任何先前的提交)。 (请注意,在合并提交E的情况下,其第一个父级为D,其第二个父级为omaster左侧将其提交到左侧。对于master上的所有合并,第一个父级位于同一行,而第二个父级位于feature下方和左侧。)

这是否足够取决于您(和其他人)在提交过程中的纪律。如果master有自己的内部分支和合并,您可能会有一个更像这样的图表:

... --X---Y---*-----*-o---o---------*--*   <-- master
       \   \ /     /   \           /  /
        \   Z     /     \         /  /
         \       /       \       /  /
          A--B--C--D------E--F--G--H       <-- feature

现在您不能轻易地使用第一个/非第一个父测试,因为提交YZ必然是{{1}上合并的第二个父级},但请注意,master无法首先遍历Z featureE是直接在&#34;上的合并提交&#34}。 feature,其第二个父提交位于master

换句话说,我直接在&#34;上使用了一个稍微特别的短语&#34;一个分支,用于标识从分支提示开始可查找的提交,以及仅通过第一个父级向后工作的提交。对于feature,这些{仍然是AH,加上不幸的是X及其(第一个)父母。

git rev-list命令,这是git非常重要的命令之一 - 它是git rev-parse的大姐姐版本,也是非常重要的 - 有一个标志,专门实现这个&#34;直接在&#34;概念,即--first-parent。 rev-list命令通过提交图的某些部分遍历 2 :你告诉它一些提交开始,它发现提交的父母和那些父母&#39 ;父母和他们的父母,等等。如果您指定--first-parent,则只会找到每个提交的第一个父级。 (这显然只会影响合并提交,因为根据定义,非合并提交最多只有一个父提交。)

在您的特定情况下,您还表示您希望消除合并您的feature分支,即合并直接在feature上的提交。要执行此操作,只需告诉rev-list使用--no-merges从其输出中排除合并提交。

消除提交X及更早版本有点困难,但事实证明, 难以提供知道哪些分支包含X等提交,你想要排除,是的。 --not参数(包括几种替代拼写)告诉rev-list提交 exclude 的内容。所以:

git rev-list --first-parent feature --not master --no-merges

直接识别提交列表&#34;&#34;功能(AH)但直接在masterX及更早版本),然后仅列出那些不合并的功能(从而消除了提交E)。

您可能希望进一步减少这种情况,例如,可能使用提交时间戳(--since--until)。您可能(或可能不)想要更改列出修订的顺序,例如,可能使用--topo-order将它们按图形顺序而不是日期顺序放置。

将其与git log

放在一起

幸运的是,git log有效地使用您的修订说明符调用git rev-list。因此,不必首先使用git rev-list,然后以某种方式将结果提供给git log,您可以将这些相同的说明符赋予git log。事实上,在确定你想要的限制器时(使用--since--until之类的东西),git log更容易使用,因为大量的原始SHA-1是对人类没有多大用处。


1 实际上,保留分支运动历史的reflog确实能让你知道,但只能在一台本地机器上运行;问题是这必须在不同的系统上完成,其中reflog不可用。在任何情况下,reflog条目都会在一段时间后过期,默认情况下会在90天内过期。

2 当然,除非您使用--no-walk