显示最初在分支上进行的提交(过滤掉合并的提交)
Show commits made on branch originally (filter out merged commits)
在一个有多个分支的 git 仓库中,我将一个功能分支合并到 master 中,然后从 master 合并回功能分支。 我现在如何使用 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
过滤没有帮助,因为我正在审查一个特定的功能分支。
TL;DR:您需要 --first-parent
(参见 git rev-list
documentation)和其他一些选择标准。
Git 不跟踪 "on which branch a commit was actually made"。例如,假设您在分支 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
的顶端添加一个新提交,即使该提交根本不在分支上。或者,假设有两个分支 B1
和 B2
都指向提交 C7
:
... <- C5 <- C6 <- C7 <-- B1, B2
如果您进行新提交 C8
,其 parent 为 C7
,则使分支 B2
指向 C8
,该提交现在开始分支B2
。如果您在分支 B1
上进行了新提交,则 B1
也指向 C8
,但如果您随后使用 git reset
将 B1
移回指向C7
,不再可能告诉 1 提交最初是在 B1
而不是 B2
.
综上所述,如果您在合并分支时保持良好的一致性,则可以在提交图上执行图遍历,找到提交 "between" 特定的合并,然后处理一个特定的 parent链,以检测提交是 可能 done-on 的分支。例如,如前所述,使用 feature
和 master
,假设提交始终在 feature
上进行,然后 feature
定期合并到 master
和 --no-ff
以确保 master
上的每个 merge-commit 都是真正的合并提交,而不仅仅是 fast-forward。然后图形模式将如下所示:
... --X--*------*-o---o-----*--* <-- master
\ / \ / /
A--B--C--D--E--F--G--H <-- feature
(其中 "time" 随着向右移动而增加,*
节点是在分支 master
上进行的合并提交,o
节点代表分支上的其他提交大师)。
在这种情况下,您可以通过从 feature
的提示(提交 H
)开始并仅遍历 [=178] 来找到(可能)在 feature
上进行的提交=] 提交——这些是 A
到 H
——然后丢弃可以通过仅遵循 master
上的 first-parent 提交找到的提交。第二个标准消除了上面标记为 X
的提交(以及任何之前的提交)。 (注意在merge commit E
的情况下,它的first parent是D
,它的second parent 是在 master
左侧的 o
提交。对于 master
上的所有合并, 第一个 parent 在同一行,second parent 在 feature
的左下方。)
这是否足够取决于您(和其他人)在提交过程中的纪律程度。如果 master
有自己的内部 branch-and-merges,你可能有一个更像这样的图表:
... --X---Y---*-----*-o---o---------*--* <-- master
\ \ / / \ / /
\ Z / \ / /
\ / \ / /
A--B--C--D------E--F--G--H <-- feature
现在你不能简单地使用 first/not-first parent 测试,因为提交 Y
或 Z
必然是第二个 parent master
上的合并,但请注意,如果不先遍历 E
,则无法从 feature
访问 Z
,这是合并提交 "directly on" feature
的第二个 parent 提交在 master
.
换句话说,我使用稍微特殊的短语 "directly on" a branch 来识别 find-able 的提交,方法是从分支尖端开始,然后仅通过第一个 parent 向后工作.对于 feature
,这些(仍然)是 A
到 H
,加上不幸的是 X
及其(第一个)parents.
git rev-list
命令,它是 git 非常重要的命令之一——它是 git rev-parse
的 big-sister 版本,也是非常重要的——有一个标志专门实现了这个"directly on"概念,即--first-parent
。 rev-list 命令遍历提交图的某些部分2:您告诉它从某个提交开始,它会发现提交的 parents ,以及那些 parents' parents,以及他们的 parents,等等。如果您指定 --first-parent
,它只会找到每个提交的 first parent。 (这显然只影响合并提交,因为根据定义,一个 non-merge 提交最多有一个 parent 提交。)
在您的特定情况下,您还说过您希望消除合并 到 您的 feature
分支,即合并直接在 [=35] 上的提交=].为此,只需使用 --no-merges
.
告诉 rev-list 从其输出中排除合并提交
消除提交 X
和更早版本有点困难,但事实证明,如果您知道哪个分支包含像 X
,您要排除的是打开的。 --not
参数(包括几个替代拼写)告诉 rev-list 提交给 exclude 的内容。所以:
git rev-list --first-parent feature --not master --no-merges
标识提交列表 "directly on" 功能(A
到 H
)但 不是 直接在 master
上(X
和更早版本),然后只列出那些不是合并的(从而消除提交 E
)。
您可能希望进一步削减它,例如,可能通过使用提交时间戳(--since
和 --until
)。您可能(或可能不)想要更改列出修订的顺序,也许使用 --topo-order
将它们放在图形顺序中例如,r 而不是日期顺序。
将其与 git log
放在一起
幸运的是,git log
使用您的修订说明符有效地调用了 git rev-list
。因此,不必先使用 git rev-list
,然后以某种方式将结果提供给 git log
,您只需将这些相同的说明符提供给 git log
。事实上,在确定你想要的限制器时(使用 --since
和 --until
之类的东西),git log
更容易使用,因为一大堆原始 SHA-1 是对人类不是很有用。
1实际上,保留分支运动历史记录的 reflog 确实让您能够分辨,但仅限于一台本地机器;这个问题说这必须在不同的系统上完成,reflogs 不可用。在任何情况下,reflog 条目都会在一段时间后过期,此处感兴趣的条目默认为 90 天。
2当然除非你用--no-walk
.
在一个有多个分支的 git 仓库中,我将一个功能分支合并到 master 中,然后从 master 合并回功能分支。 我现在如何使用 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
过滤没有帮助,因为我正在审查一个特定的功能分支。
TL;DR:您需要 --first-parent
(参见 git rev-list
documentation)和其他一些选择标准。
Git 不跟踪 "on which branch a commit was actually made"。例如,假设您在分支 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
的顶端添加一个新提交,即使该提交根本不在分支上。或者,假设有两个分支 B1
和 B2
都指向提交 C7
:
... <- C5 <- C6 <- C7 <-- B1, B2
如果您进行新提交 C8
,其 parent 为 C7
,则使分支 B2
指向 C8
,该提交现在开始分支B2
。如果您在分支 B1
上进行了新提交,则 B1
也指向 C8
,但如果您随后使用 git reset
将 B1
移回指向C7
,不再可能告诉 1 提交最初是在 B1
而不是 B2
.
综上所述,如果您在合并分支时保持良好的一致性,则可以在提交图上执行图遍历,找到提交 "between" 特定的合并,然后处理一个特定的 parent链,以检测提交是 可能 done-on 的分支。例如,如前所述,使用 feature
和 master
,假设提交始终在 feature
上进行,然后 feature
定期合并到 master
和 --no-ff
以确保 master
上的每个 merge-commit 都是真正的合并提交,而不仅仅是 fast-forward。然后图形模式将如下所示:
... --X--*------*-o---o-----*--* <-- master
\ / \ / /
A--B--C--D--E--F--G--H <-- feature
(其中 "time" 随着向右移动而增加,*
节点是在分支 master
上进行的合并提交,o
节点代表分支上的其他提交大师)。
在这种情况下,您可以通过从 feature
的提示(提交 H
)开始并仅遍历 [=178] 来找到(可能)在 feature
上进行的提交=] 提交——这些是 A
到 H
——然后丢弃可以通过仅遵循 master
上的 first-parent 提交找到的提交。第二个标准消除了上面标记为 X
的提交(以及任何之前的提交)。 (注意在merge commit E
的情况下,它的first parent是D
,它的second parent 是在 master
左侧的 o
提交。对于 master
上的所有合并, 第一个 parent 在同一行,second parent 在 feature
的左下方。)
这是否足够取决于您(和其他人)在提交过程中的纪律程度。如果 master
有自己的内部 branch-and-merges,你可能有一个更像这样的图表:
... --X---Y---*-----*-o---o---------*--* <-- master
\ \ / / \ / /
\ Z / \ / /
\ / \ / /
A--B--C--D------E--F--G--H <-- feature
现在你不能简单地使用 first/not-first parent 测试,因为提交 Y
或 Z
必然是第二个 parent master
上的合并,但请注意,如果不先遍历 E
,则无法从 feature
访问 Z
,这是合并提交 "directly on" feature
的第二个 parent 提交在 master
.
换句话说,我使用稍微特殊的短语 "directly on" a branch 来识别 find-able 的提交,方法是从分支尖端开始,然后仅通过第一个 parent 向后工作.对于 feature
,这些(仍然)是 A
到 H
,加上不幸的是 X
及其(第一个)parents.
git rev-list
命令,它是 git 非常重要的命令之一——它是 git rev-parse
的 big-sister 版本,也是非常重要的——有一个标志专门实现了这个"directly on"概念,即--first-parent
。 rev-list 命令遍历提交图的某些部分2:您告诉它从某个提交开始,它会发现提交的 parents ,以及那些 parents' parents,以及他们的 parents,等等。如果您指定 --first-parent
,它只会找到每个提交的 first parent。 (这显然只影响合并提交,因为根据定义,一个 non-merge 提交最多有一个 parent 提交。)
在您的特定情况下,您还说过您希望消除合并 到 您的 feature
分支,即合并直接在 [=35] 上的提交=].为此,只需使用 --no-merges
.
消除提交 X
和更早版本有点困难,但事实证明,如果您知道哪个分支包含像 X
,您要排除的是打开的。 --not
参数(包括几个替代拼写)告诉 rev-list 提交给 exclude 的内容。所以:
git rev-list --first-parent feature --not master --no-merges
标识提交列表 "directly on" 功能(A
到 H
)但 不是 直接在 master
上(X
和更早版本),然后只列出那些不是合并的(从而消除提交 E
)。
您可能希望进一步削减它,例如,可能通过使用提交时间戳(--since
和 --until
)。您可能(或可能不)想要更改列出修订的顺序,也许使用 --topo-order
将它们放在图形顺序中例如,r 而不是日期顺序。
将其与 git log
放在一起
幸运的是,git log
使用您的修订说明符有效地调用了 git rev-list
。因此,不必先使用 git rev-list
,然后以某种方式将结果提供给 git log
,您只需将这些相同的说明符提供给 git log
。事实上,在确定你想要的限制器时(使用 --since
和 --until
之类的东西),git log
更容易使用,因为一大堆原始 SHA-1 是对人类不是很有用。
1实际上,保留分支运动历史记录的 reflog 确实让您能够分辨,但仅限于一台本地机器;这个问题说这必须在不同的系统上完成,reflogs 不可用。在任何情况下,reflog 条目都会在一段时间后过期,此处感兴趣的条目默认为 90 天。
2当然除非你用--no-walk
.