Git 日志 : excluding commits from a specific merge

标签 git git-log

我正在尝试找出如何在两个标签之间打印出 git 日志,排除在一个特定 merge 提交中 merge 的所有提交。

例如。如果我的提交日志看起来像这样:

   TAGA                                        TAGB
    |     C---F---H---K           Q---T---V     |
    v    /             \         /         \    v
    A---B---D---G---J---L---M---O---R---U---W---X
             \     /         \         /
              E---I           N---P---S

而且我想要排除在 merge 提交 L 时引入主干的所有提交。 (所以在这个例子中,我想排除 C,F,H,K)。

目前我的 git 行看起来像这样:

git log --oneline --no-merges TAGB ^TAGA

这将列出两个标签之间的所有提交(注意,我排除了 merge 提交本身,这就是 J、L、U 和 W 不存在的原因。):

A,B,C,D,E,F,G,H,I,K,M,N,O,P,Q,R,S,T,V,X

有谁知道排除 C,F,H & K 的方法吗?即:

A,B,D,E,G,I,M,N,O,P,Q,R,S,T,V,X

如有任何帮助,我们将不胜感激。

最佳答案

没有便宜的、一体化的 Git 表达式方法可以做到这一点。图行走代码要么遵循 --first-parent仅(如 Vimsha's answer )或跟随 merge 的所有父级。因此,排他性 ^K (或 ^L^2 或以其他方式命名提交 K )具有修剪 所有 可从 K 访问的提交的副作用,而不仅仅是 C--F--H--K顺序。

我们仍然可以获得我们想要的列表,只是需要更多的工作。首先,生成有趣哈希的完整列表:

tempfile1=$(mktemp)
git rev-list --no-merges TAGB ^TAGA > $tempfile1

(请注意 git loggit rev-list 几乎是相同的命令,并且是从相同的来源构建的;它们之间的主要区别在于 rev-list 只打印完整的哈希 ID)。接下来,生成要排除的完整哈希列表:

tempfile2=$(mktemp)
git rev-list --no-merges K ^B > $tempfile2

(你是怎么找到 B 的?好吧,我想知道,你一开始是怎么找到 K 的?——但是一旦你找到了 K,并且知道它比如说,L^2BL^L^2 之间的 merge 基础,所以你可以用git merge-base 和这两个名称找到它的ID。)我们真的不需要--no-merges在此示例中,但在更复杂的示例中,我们可能需要它和/或 --first-parent以及。 (编辑以添加注释:当然我们永远不需要 --no-merges :这是一个排除列表, merge 已被排除。)

现在我们需要“在临时文件 1 中找到的所有哈希值,不包括在临时文件 2 中的任何哈希值”,执行此操作的 Unix 工具集命令是 comm . (Linux 变体要求对输入进行排序并实际检查,因此您需要 --nocheck-order 来打败它。comm 使用的底层算法只需要文件的行是按照相同的顺序,情况就是这样。或者,您可以对两个文件进行排序:例如 sort -o $tempfile1 $tempfile1。但这样做既昂贵又不必要。)

The comm utility reads file1 and file2, which should be sorted lexically, and produces three text columns as output: lines only in file1; lines only in file2; and lines in both files.

我们需要“仅在 file1 中的行”,即丢弃出现在 file2 中的行。那将是“文本第 1 列”,这似乎需要更多的后处理,但幸运的是:

-1      Suppress printing of column 1.

-2      Suppress printing of column 2.

-3      Suppress printing of column 3.

所以我们取消第 2 列和第 3 列:

comm -23 $tempfile1 $tempfile2

这会在标准输出上生成我们想要的 SHA-1 的完整列表 git log显示。

最后一步是将此输出 Hook 到 git log --oneline ,这很简单:

git log --oneline --stdin --no-walk

--no-walk防止 git log (或 git rev-list )完全不进行提交图遍历,这正是我们想要的,因为我们为它提供了要访问的每个提交的完整列表。 --stdin提供我们从 comm 获得的修订.

我们现在需要的只是一个小的 shell 打包来清理临时文件:

#! /bin/sh -e

# note the -e option -- this avoids the need for a lot of || exit
# clauses (to handle any early failures)

tempfile1=$(mktemp)
trap "rm -f $tempfile1" 0 1 2 3 15
tempfile2=$(mktemp)
trap "rm -f $tempfile1 $tempfile2" 0 1 2 3 15

git rev-list --no-merges TAGB ^TAGA > $tempfile1
git rev-list --no-merges K ^B > $tempfile2
comm -23 $tempfile1 $tempfile2 | git log --oneline --stdin --no-walk

(当然,这都是未经测试的,它省略了您想要查找或获取参数的地方,这两个标签和 merge 提交 L 您希望单边排除,以及边号为 1 或 2。根据需要想象一下。)

关于Git 日志 : excluding commits from a specific merge,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40384934/

相关文章:

git - 看不到远程分支,.git/config 有问题吗?

git - 将 Mercurial 文件夹转换为 Git 存储库

git - 如何在一次操作中创建功能分支并重置为 origin/master?

git - 如何让git显示所有本地分支的最近n次提交

Git 修订范围显示警告

git - 如何重现 git log --oneline --decorate 的格式?

git - Go:无法在符号链接(symbolic link)中打包

git - zlib 在共享主机上安装 GIT 时出错

git - 找出我们尝试挑选的提​​交的依赖项

git - 一个 git 日志历史图表,每次提交一行,彩色,带日期