如何将一个提交与其父提交进行比较?

513

除了编写别名或脚本,是否有更短的命令可以获取特定提交的差异?

git diff 15dc8^..15dc8

如果你只提供单个提交ID git diff 15dc8,它将把该提交与HEAD进行比较。


最酷的事情是,这将与“git difftool”一起使用,利用工具来显示差异。 - orip
作为参考,另一个问题的答案说明了如何设置一个基于bash的别名来简化上述操作:https://dev59.com/4HA75IYBdhLWcg3wYYBQ - Nick
8个回答

696

使用git show $COMMIT命令。它会显示该提交的日志信息和差异。


48
很遗憾它不能使用 difftool :( - orip
1
@orip 你可以随时将GIT_EXTERNAL_DIFF设置为一个与你的difftool执行相同操作的脚本。 - slacy
7
我更喜欢JakubNarebski的答案,因为他给出的提交表达式在许多情况下都能够工作:https://dev59.com/RHRC5IYBdhLWcg3wAcbU#449128 - RichVel
1
如果没有显示差异,那么可能没有实际更改,例如合并提交。 - Devin Rhode
7
问题是:“是否有一种更短的命令来获取特定提交的差异?”,这个问题的答案已经回答了。 - mipadi
显示剩余4条评论

498

使用:

git diff 15dc8^!
根据git-rev-parse(1)手册的以下片段(或现代Git中的gitrevisions(7)手册),存在另外两个用于命名由提交及其父提交组成的集合的简写。r1^@符号表示所有r1的父提交,而r1^!则包括提交r1,但不包括其所有父提交。
这意味着您可以在Git需要修订时的任何地方将15dc8^!用作15dc8^..15dc8的简写。对于diff命令,git diff 15dc8^..15dc8被理解为git diff 15dc8^ 15dc8,这意味着它计算提交(15dc8)和其父提交(15dc8^)之间的差异。 注意:在git-rev-parse(1)手册中的描述涉及修订范围,需要在多个父提交的合并提交中工作。那么r1^!就是“r1 --not r1^@”,即“r1 ^r1^1 ^r1^2 ...”。
此外,可以使用git show COMMIT获取提交的描述和差异。如果只想获得差异,则可以使用git diff-tree -p COMMIT

9
这应该是被接受的答案,比较整洁。但是,git-rev-parse提取的最后一句话相当令人困惑——似乎意思是“从此提交的父提交到此提交的范围”。 - RichVel
3
@RichVel:有点令人困惑,因为它还试图描述提交具有多个父级(即合并提交)的情况。r1 ^!在这种情况下也能够按预期工作。 - Jakub Narębski
1
@JakubNarębski:很好的观点,也许您可以编辑您的答案,总结一下单亲家庭和多亲家庭情况的理解-分别对每个声明进行说明可能更容易理解。 - RichVel
1
@JakubNarębski:是的,好多了!我现在一直使用这个快捷方式 - 谢谢。 - RichVel
1
“^!” 父级简写符号在普通提交的 difftool 中正常工作,但对于合并提交,差异会被反转。为什么会这样? - hIpPy
显示剩余2条评论

60

如果你知道需要回溯多远,你可以尝试这样做:

# Current branch vs. parent
git diff HEAD^ HEAD

# Current branch, diff between commits 2 and 3 times back
git diff HEAD~3 HEAD~2

之前的提交工作原理如下:

# Parent of HEAD
git show HEAD^1

# Grandparent
git show HEAD^2

你可以通过很多方式指定提交记录:

# Great grandparent
git show HEAD~3

详见此页面


6
如果HEAD^1是爸爸,那么HEAD^2就是妈妈,而HEAD~2则表示爷爷。请注意,HEAD^2并不是祖父级别的提交。 - Binarian

12

mipadi 指出,你可以使用git show $COMMIT命令来查看提交的差异,但是它还会显示一些头部信息和提交消息。如果你想要一个简单的差异,可以使用git show --pretty=format:%b $COMMIT

显然,这不是一个非常简短的命令,因此我将其保存在我的.gitconfig文件中作为一个别名。

    [alias]
      sd = show --pretty=format:%b

这使我能够使用git sd $COMMIT显示差异


1
这个别名可以包括 --color,使其更易于阅读:sd = show --color --pretty=format:%b - RichVel
@RichVel 的确!非常好的观点。如果你在 git 中默认启用了颜色,你就不需要使用这个开关。这也是我通常做的事情。 - Øystein Steimler

6
许多提到的示例(例如git diff 15dc8^!git diff 15dc8^..15dc8)在使用Z shell并设置了extendedglob选项时无法正常工作。您可以通过以下三种方式之一修复它:
  1. unsetopt extendedglob(和/或从.zshrc中删除它)
  2. setopt NO_NOMATCH(和/或在.zshrc中设置它)
  3. 每次用反斜杠转义插入符号和感叹号,例如:git diff 15dc8\^\!

3
git diff 15dc8 15dce~1

~1 表示“父级”, ~2 表示“祖先级”等。


3

保罗的解决方案做到了我所希望的。

$ git diff HEAD^1

此外,添加别名非常有用,例如hobs mentioned。如果将以下内容放入~/.gitconfig文件的[alias]部分,则可以使用缩写查看头部和上一个版本之间的差异。
[alias]
    diff-last = diff HEAD^1

然后运行 $ git diff-last 就能得到你的结果。请注意,这也会包括你尚未提交的任何更改以及提交之间的差异。如果您想要忽略尚未提交的更改,则可以使用diff直接比较HEAD与其父级:

$ git diff HEAD^1 HEAD

0

这里使用了别名,所以并没有直接回答你的问题,但我发现这对于实现你想要的功能非常有用...

alias gitdiff-1="git log --reverse|grep commit|cut -d ' ' -f2|tail -n 2|head -n 2|xargs echo|sed -e 's/\s/../'|xargs -n 1 git diff"
alias gitdiff-2="git log --reverse|grep commit|cut -d ' ' -f2|tail -n 3|head -n 2|xargs echo|sed -e 's/\s/../'|xargs -n 1 git diff"
alias gitdiff-3="git log --reverse|grep commit|cut -d ' ' -f2|tail -n 4|head -n 2|xargs echo|sed -e 's/\s/../'|xargs -n 1 git diff"

alias gitlog-1="git log --reverse|grep commit|cut -d ' ' -f2|tail -n 2|head -n 2|xargs echo|sed -e 's/\s/../'|xargs -n 1 git log --summary"
alias gitlog-2="git log --reverse|grep commit|cut -d ' ' -f2|tail -n 3|head -n 2|xargs echo|sed -e 's/\s/../'|xargs -n 1 git log --summary"
alias gitlog-3="git log --reverse|grep commit|cut -d ' ' -f2|tail -n 4|head -n 2|xargs echo|sed -e 's/\s/../'|xargs -n 1 git log --summary"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接