git log
有一些非常有用的commit-limiting options,例如--no-merges
和--first-parent
。我希望能够在为一系列提交生成累积差异补丁/ stat / numstat时使用这些选项。
使用以下命令:
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
差异不是累积的(每次提交都会单独列出更改)。
使用以下命令:
git diff --patch 29665b0..0b76a27
git diff --stat 29665b0..0b76a27
git diff --numstat 29665b0..0b76a27
diff 是累积的,但不幸的是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
其中--pretty=format:%h
输出匹配提交的哈希值。
感谢@torek和@twalberg,我现在更清楚地了解git diff
的操作。范围语法29665b0..0b76a27
确实具有误导性,我现在明白,它实际上并没有在一系列提交中执行累积差异。通过docs,我发现了这个:
" DIFF"是关于比较两个端点,而不是范围,范围符号(
<commit>..<commit>
和<commit>...<commit>
)并不意味着&#34;指定范围&#34中定义的范围; gitrevisions(7)中的部分。
考虑到这一点,我将重新解释我的问题。使用这些命令:
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
每个匹配的提交都会单独列出更改。如何组合这些单独的更改,以生成累积补丁/ stat / numstat?
链接possible duplicate question的答案很有帮助,建议一个解决方案:创建一个临时分支,挑选相关的提交,然后生成差异。
我刚刚发布了一个使用这种技术的答案,但我仍然有兴趣知道是否有一个不需要临时分支的解决方案?
答案 0 :(得分:2)
这里至少有一个基本的误解。具体而言,git diff
根本不是累积的:相反,它只是成对的。
具体来说,这两个命令做同样的事情:
git diff rev1 rev2
git diff rev1..rev2
也就是说,在git diff
中,首先确实没有范围这样的东西。
有了这个,让我们来看看git log
的幕后故事。 git log
对范围的作用实际上是 1 将范围传递给git rev-list
,这会生成范围内每个转速的列表,并沿途应用修改器: / p>
git rev-list 29665b0..0b76a27
吐出0b76a27
可从29665b0
无法访问的每个转化次数。添加--first-parent
,--max-parents=1
(又名--no-merges
)等会过滤掉此处列出的部分内容。
最终结果会返回git log
,然后会按顺序查看每个修订版git rev-list
将它们吐出来 - 这也可以通过--date-order
和--topo-order
来控制等等;请参阅documentation for git rev-list - 并显示每个日志条目,可能还有由git diff-tree
生成的差异(对于单父提交,将提交与其父级进行比较)。
然后,您可以直接调用git rev-list
,然后从其输出中剥离顶部和底部修订。 (在这种特殊情况下,您可能也需要--topo-order
,以确保最后一次转换确实是最早的,无论日期如何,都是图形式的。)例如,在脚本中:
#! /bin/sh
tempfile=$(mktemp -t mydiff)
trap "rm -f $tempfile" 1 2 3 15
git rev-list 29665b0..0b76a27 --first-parent --no-merges --topo-order > $tempfile
# remember that the first rev listed is the last rev in the range
last=$(head -1 $tempfile)
first=$(tail -1 $tempfile)
rm -f $tempfile # done with it, don't leave it around while showing diff
git diff $first $last
通过使用git rev-parse
解析选项并将它们拆分为差异选项和转换列表选项,您可以获得更多的体验,但这超出了您的需求。上面要改进的主要是摆脱硬编码的修订范围。
1 一些git命令确实确实将参数传递给git rev-list
,因为它们只是使用git rev-list
的shell脚本和其他git命令来处理这个。其他的是一起构建的,因此git log
和git rev-list
实际上是一个二进制文件,一部分将工作交给另一部分,但不调用新程序。
在任何情况下,请注意git log master
只需将master
关闭到git rev-list
,这会生成一个可从分支标签master
到达的所有转速的列表。如果您添加--no-walk
,则git rev-list
只会生成一次转化,因此git log
仅显示该修订版。
答案 1 :(得分:0)
# Create a temporary branch to mark the start of the cherry-picked commits
git branch tmpstart
# Create and checkout a temporary branch for the cherry-picked commits
git checkout -b tmpend
# Use git log to filter the range of commits with the desired
# commit-limiting options, and then cherry-pick each matching commit
git log \
--first-parent \ # Commit-limiting
--no-merges \ # Commit-limiting
--reverse \ # Reverse the order (ascending chronological order)
--pretty=format:%h \ # Output the abbreviated hash of each matching commit
29665b0..0b76a27 \ # Range of commits
| xargs -n 1 git cherry-pick
# Generate the patch/stat/numstat of the cherry-picked commits
git diff --patch tmpstart tmpend
git diff --stat tmpstart tmpend
git diff --numstat tmpstart tmpend