如何使用“git”命令获取单个提交X修改单个文件Y的统一差异?

5
我正在编写代码以自动运行git命令并学习git。我是否误读了手册,或者我想做的事情不可行?下面的命令将告诉我MYFILE在两个提交之间如何更改:git diff COMMIT1..COMMIT2 -- MYFILE。很好。但是,假设我只想询问COMMITX如何更改文件,而不指定先前的提交。在我的想象中,语法应该像这样:
git diff COMMITX -- MYFILE

或者这样:
git diff COMMITX^..COMMITX -- MYFILE

但是上述命令对我来说无效。

下面的命令可以显示COMMITX如何更改MYFILE,但它也包括其他一些需要剥离的东西 - 比如作者、日期和提交信息。 剥离额外的内容很容易,但感觉这不应该是我需要做的事情。 是否存在某个命令可以直接实现? 我是否误解了一些简单的东西?

git show COMMITX -- MYFILE

编辑1:这里展示了我在“git bash”窗口中的实际输出。我将“show”更改为“diff”,但没有任何输出。

$ git show 789e9 -- dir1/file3.txt
提交 789e948bce733dab9605bf8eb51584e3b9a2eba3
作者:corey 
日期:2009年10月11日 星期日 -0500
我的消息
差异 --git a/dir1/file3.txt b/dir1/file3.txt 索引 a351259..cf2bd35 100644 --- a/dir1/file3.txt +++ b/dir1/file3.txt @@ -4,5 +4,7 @@ c ddd e f +一行新内容 +另一行新内容 g h
Administrator@BIOSTAR /c/temp/mygit (master) $ git diff 789e9 -- dir1/file3.txt Administrator@BIOSTAR /c/temp/mygit (master)

我知道你已经接受了一个答案,但我想确保你知道 - 这完全可以使用 git-diff 实现。请看下面! - Cascabel
2
"git diff COMMIT -- FILE" 命令用于比较 COMMIT 中的 FILE 版本和你当前工作区域中的 FILE 版本... 这可能不是你想要的。 - Jakub Narębski
@Jerromi - 请看我的评论回复。对我来说不起作用。 - Corey Trager
4个回答

6

尝试:

git show --pretty=format: <commitid> -- <file>

这是它的外观:

diff --git a/config.y b/config.y
index 7750514..f051b99 100644
--- a/config.y
+++ b/config.y
@@ -454,8 +454,8 @@ definegame : TYPE_DEFINE_GAME '{'
        }
        game_definitions '}'
        {
-           num_games = ncnf;
            ncnf++;
+           num_games = ncnf;
        }
        ;

在开头仍有一个空行(由于markdown的限制这里未显示),但是patch会忽略它(事实上,默认的git show输出中也会忽略标题部分)。您还可以通过使用tail -n +2来删除该行。

--pretty=oneline也很有用:

3ed347de4c6e0e3230f651f82aabf964c6d16100 Fix a bug where more than one defined game didn't show up or showed gibberish
diff --git a/config.y b/config.y
index 7750514..f051b99 100644
--- a/config.y
+++ b/config.y
@@ -454,8 +454,8 @@ definegame : TYPE_DEFINE_GAME '{'
        }
        game_definitions '}'
        {
-           num_games = ncnf;
            ncnf++;
+           num_games = ncnf;
        }
        ;

话虽如此,如果你正在为提交补丁格式化内容,不要删除这些内容。实际上,使用git format-patch并享受它。第三方修补工具将快乐地忽略那些额外的元数据,对于使用git的项目,git apply将使用您提供的提交消息和作者行,使其易于应用。


似乎它正在工作。我采纳了你的答案,回到“git show”手册页面,在我新获得的启示状态下,试图看看是否能够在页面上“看到”你的答案,因为我确切地知道我在寻找什么。但仍然有些棘手->没有任何格式规范的“format:”。额外加分的是,“作者”和“提交者”的区别是什么? - Corey Trager
在这里找到了关于作者/提交者区别的解释:http://book.git-scm.com/1_the_git_object_model.html。 - Corey Trager
这实在是有点过度了,除非你真的想为提交创建一个补丁,但如果你只是对单个文件进行差异比较,这是不太可能的。git-diff被设计用来完成很多任务,包括这个任务。 - Cascabel

5

git diff COMMIT^..COMMIT file 或者 git diff COMMIT^..COMMIT -- file 在我使用 git 1.6.3.3 版本时都能正常工作。Jakub Narębski 提供更新:你也可以写成 git diff COMMIT^! -- file

$ git log --oneline b8ad655^!
b8ad655 Bring in the "SimpleMenu" loader plugin


$ git diff b8ad655^! lib/WWW/MenuGrinder/Plugin/SimpleLoader.pm
diff --git a/WWW-MenuGrinder/lib/WWW/MenuGrinder/Plugin/SimpleLoader.pm b/WWW-MenuGrinder/lib/WWW/MenuGrinder/Plugin/SimpleLoader.pm                                                                                                                        
new file mode 100644                                                                                                          
index 0000000..14f6cd8                                                                                                        
--- /dev/null                                                                                                                 
+++ b/WWW-MenuGrinder/lib/WWW/MenuGrinder/Plugin/SimpleLoader.pm
[...]

git diff 显示当前工作树与提交之间的差异,而不是从提交到其父级的更改。 - bdonlan
如果有一个扩展程序可以允许 git diff ^..COMMIT 作为 svn diff -c rev 的类比,那将非常可爱 :) - hobbs
虽然我的问题不是其他stackoverflow问题的完全重复,但它很相似。我不能指望git基于svn类比是可预测的,但如果一个git命令的行为可以根据其他git命令的行为更可预测一些就好了。 - Corey Trager
@bdonlan:那只是默认的操作模式。看一下手册页面的顶部部分,它可以显示两个任意树(例如提交)之间的差异,树和工作树之间的差异,树和索引之间的差异,或者索引和工作树之间的差异。 - Cascabel
1
@hobbs:有的,它被称为git diff COMMIT^!(参见git-rev-parse手册,第“Specifying ranges”部分)。 - Jakub Narębski

1

您无需像使用git-show这样的解决方法-您的语法只是略有偏差。 git-diff显示两个命名提交之间的差异。 另一方面,..表示“...之间的提交范围”。 正确的语法是:

git diff COMMITX^ COMMIT -- MYFILE

话虽如此,对于我来说使用 .. 是有效的。(我在 git.git 中测试了 git diff master^..master -- git-add--interactive.perl)可能以前不是这样,但至少自从 git 移动到索引版本 2(在 v1.5.1 和 v1.5.2 之间)以来就一直有效 - 对我来说回溯测试这之前会很麻烦。


实际上,“git diff A..B” 很长一段时间以来就像“git diff A B”一样工作,主要是为了便于将修订 [范围] 剪切并粘贴到 diff 中,例如从 git-fetch 输出。 - Jakub Narębski
“git diff”文档(http://www.kernel.org/pub/software/scm/git/docs/git-diff.html)中说,“COMMIT..COMMIT”与“COMMIT COMMIT”是同义词。但是当我写“COMMIT^”时,两者都不起作用。只有在直接指定前一个提交时,它们才能正常工作。我正在使用Windows上的msysgit,git版本为1.6.4。 - Corey Trager
回顾所有的测试用例,看起来 diff 运行良好,但是可能修订解析存在问题 - 在其他情况下 COMMIT^ 是否有效? - Cascabel
@Corey Trager:你在使用Git时用的是哪个shell?也许是因为你的shell对^和/或!字符做了一些奇怪的事情... 你尝试过例如"COMMIT^"'COMMIT^'(使用双引号或单引号)吗? - Jakub Narębski

0

我通常只是这样做:

git diff > unified.diff

然后在我最喜欢的统一差异查看器中打开它。


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