git log有一些非常有用的提交限制选项,例如--no-merges和--first-parent。在为一系列提交生成累积差异补丁/统计/数字统计时,我希望能够使用这些选项。
使用这些命令:
git log --oneline --first-parent --no-merges --patch 29665b0..0b76a27
git log --oneline --first-parent --no-merges --stat 29665b0..0b76a27
git log --oneline --first-parent --no-merges --numstat 29665b0..0b76a27
Run Code Online (Sandbox Code Playgroud)
差异不是累积的(每个提交的更改单独列出)。
使用这些命令:
git diff --patch 29665b0..0b76a27
git diff --stat 29665b0..0b76a27
git diff --numstat 29665b0..0b76a27
Run Code Online (Sandbox Code Playgroud)
差异是累积的,但不幸的git diff是不支持提交限制选项。
所以我想要的是git diff结合git log.
我的一个想法是用来git log生成一个提交哈希列表,然后以某种方式将该列表通过管道git diff生成指定提交的累积差异。像这样的东西(显然这种管道散列的方法git diff实际上不起作用):
git log --pretty=format:%h --first-parent --no-merges 29665b0..0b76a27 | git diff
Run Code Online (Sandbox Code Playgroud)
其中--pretty=format:%h输出匹配提交的哈希值。
感谢@torek 和@twalberg,我现在git diff更清楚地了解了的操作。范围语法29665b0..0b76a27确实具有误导性,我现在明白它实际上并没有在一系列提交上执行累积差异。查看文档,我发现了这个:
"diff" 是关于比较两个端点,而不是范围,范围符号 (
<commit>..<commit>and<commit>...<commit>) 并不意味着gitrevisions(7) 的" SPECIFYING RANGES" 部分中定义的范围。
考虑到这一点,我将重新表述我的问题。使用这些命令:
git log --oneline --first-parent --no-merges --patch 29665b0..0b76a27
git log --oneline --first-parent --no-merges --stat 29665b0..0b76a27
git log --oneline --first-parent --no-merges --numstat 29665b0..0b76a27
Run Code Online (Sandbox Code Playgroud)
为每个匹配的提交单独列出更改。如何组合这些单独的更改,以生成累积补丁/统计/数字统计?
链接的可能重复问题的答案很有帮助,提出了一个解决方案:创建一个临时分支,挑选相关提交,然后生成差异。
我刚刚发布了一个使用这种技术的答案,但我仍然很想知道是否有不需要临时分支的解决方案?
这里至少存在一种基本的误解。具体来说,git diff根本不是真正的累积:相反,它只是成对的。
具体来说,这两个命令执行相同的操作:
\n\ngit diff rev1 rev2\ngit diff rev1..rev2\nRun Code Online (Sandbox Code Playgroud)\n\n也就是说,在 中git diff,实际上根本就不存在范围这样的东西。
抛开这些,让我们来看看 的幕后花絮git log。git log范围的作用实际上是1将范围交给git rev-list,这会生成范围中每个转速的列表,并一路应用修饰符:
git rev-list 29665b0..0b76a27\nRun Code Online (Sandbox Code Playgroud)\n\n吐出从0b76a27无法达到的每一个转速29665b0。添加--first-parent、--max-parents=1(又名--no-merges)等会过滤掉此处列出的一些转速。
最终结果返回给git log,然后按顺序查看每个修订版本git rev-list\xe2\x80\x94,这也可以通过--date-order等等进行控制--topo-order;请参阅git rev-list \xe2\x80\x94 的文档,并显示每个日志条目,可能还包括生成的差异git diff-tree(对于单父提交,将提交与其父提交进行比较)。
那么,您可以做的就是git rev-list直接调用您自己,然后从其输出中剥离顶部和底部修订。(在这种特殊情况下--topo-order,您可能也希望确保最后一个转数确实是最早的,从图表角度来看,无论日期如何。)例如,在脚本中:
#! /bin/sh\ntempfile=$(mktemp -t mydiff)\ntrap "rm -f $tempfile" 1 2 3 15\ngit rev-list 29665b0..0b76a27 --first-parent --no-merges --topo-order > $tempfile\n# remember that the first rev listed is the last rev in the range\nlast=$(head -1 $tempfile)\nfirst=$(tail -1 $tempfile)\nrm -f $tempfile # done with it, don\'t leave it around while showing diff\ngit diff $first $last\nRun Code Online (Sandbox Code Playgroud)\n\n通过使用git rev-parse解析选项并将它们分为 diff 选项与 rev-list 选项,您可以变得更加奇特,但这远远超出了您在这里所需要的。上述改进的主要内容是摆脱硬编码的修订范围。
1一些 git 命令确实确实将参数传递给git rev-list,因为它们只是使用git rev-list其他 git 命令来处理此问题的 shell 脚本。其他的则构建在一起,因此git log和git rev-list实际上是一个二进制文件,一个部分将工作交给另一部分,但不调用新程序。
无论如何,请注意,git log master只需将其master交给git rev-list,它就会生成从分支标签可到达的所有转速的列表master。如果您添加--no-walk,git rev-list则仅产生一版本,因此git log仅显示该版本。