git diff和git cherry的区别

5

我有两个分支:branchA和branchB

以下命令没有任何输出(包括没有差异,至少对于git diff命令):

git cherry branchA branchB
git diff branchA branchB
git diff branchB branchA

但是当我运行它时:

git cherry branchB branchA

我可以进行翻译。这段内容的意思是:我得到了一份包含加号前缀的commit id列表,例如:
+ c5f84105c242939a9d18fb9d6355534a80735277
+ 41acd0a40bfeaf3d68185a540c131838651cd889
+ 4859fd89c5dafeed6a68f0881ea6ad081a53fd68
+ 7226c9e5acf5a9d2d33b6aef3e5abf9b040f0b76
+ 4fc3206508d6ce7a19477e4c006608c78bb28801
+ 8816c66ed72da762b9b34858eec5b52a16d0ea99
+ 692d271ab07d4b92e54e72bcda09ee067654acee

有人能解释一下这是什么意思吗?想要了解为什么git diff不显示差异,但git cherry显示有差异。
3个回答

4
Git diff显示无输出,因为两个分支中的文件在内容上相同。然而,提交ID(SHA字符串)可能不同。
如果分支B中的所有提交(SHA而不是文件内容)都存在于分支A中,则git cherry branchA branxhB没有输出。然而反过来则不成立。在分支A中有一些提交不存在于分支B中,因此git cherry branchB branchA会有输出。这在这里得到了很好的解释和示例:http://jafrog.com/2012/03/22/git-cherry.html

Vishal,建议你将那篇文章的细节提取到你的答案中。这样可以使答案更直接地可用于所有人(如果你不介意的话)。 - BestPractices

3

我不确定你的困惑来自哪里,尤其是因为git diffgit cherry所执行的任务非常不同。

在Git中,通常绘制提交图表(特别是在这种情况下)可以帮助理解,例如运行git log --graph --oneline --all --decorate命令,或截取gitk的某个窗口图像,或者(这只是文档下面的建议,修改以匹配你的分支名称,但它将显示我们需要的内容):

git log --oneline --graph --boundary branchA...branchB

在某些情况下,省略--boundary可以使结果更加清晰,特别是当有很多提交在对称差异的边界上时。但对于大多数简单情况,它只是添加了合并基础提交,从而有助于阅读结果。
现在,让我们也看一下git cherry文档,其中有一个很好的例子说明我们如何使用三点对称差异符号来理解git cherry的输出。

In a situation where [branch] topic consisted of three commits, and the maintainer applied two of them, the situation might look like:

$ git log --graph --oneline --decorate --boundary origin/master...topic
* 7654321 (origin/master) upstream tip commit
[... snip some other commits ...]
* cccc111 cherry-pick of C
* aaaa111 cherry-pick of A
[... snip a lot more that has happened ...]
| * cccc000 (topic) commit C
| * bbbb000 commit B
| * aaaa000 commit A
|/
o 1234567 branch point

这里,提交1234567是包括--boundary的一个。通常情况下,三个点的标记只会选择左侧的origin/master(左侧)提交,例如7654321cccc1111aaaa111,以及右侧的master(右侧)提交,例如cccc000bbbb000aaaa000。添加--boundary将添加共享提交,实际上将这些左半部分和右半部分分开。

看看我们上游的维护人员做了什么:他接受了我们的commit Acommit C,一字不差地将它们复制到他的master中,我们在origin/master中看到了这一点。他没有接受我们的commit B,或者至少没有一字不差地接受(从这个命令和git cherry中我们无法确定他是否采用了我们修改的替代版本)。

现在看看运行git cherry的示例输出:

In such cases, git-cherry shows a concise summary of what has yet to be applied:

$ git cherry origin/master topic
- cccc000... commit C
+ bbbb000... commit B
- aaaa000... commit A
这个示例展示了我们在log [flags] origin/master...topic的列表中,右侧(topic)显示了所有三个提交,而左侧(origin/master)没有显示任何提交。对于它所显示的提交——仅在右侧的提交——每个提交都被标记为-(已取)或+(未取)。
不过,我们没有一个图形片段,因此让我们先使用当前所拥有的内容。
git cherry branchA branchB

[is empty, but]

git cherry branchB branchA

(includes at least)

+ c5f84105c242939a9d18fb9d6355534a80735277
+ 41acd0a40bfeaf3d68185a540c131838651cd889
+ 4859fd89c5dafeed6a68f0881ea6ad081a53fd68
+ 7226c9e5acf5a9d2d33b6aef3e5abf9b040f0b76
+ 4fc3206508d6ce7a19477e4c006608c78bb28801
+ 8816c66ed72da762b9b34858eec5b52a16d0ea99
+ 692d271ab07d4b92e54e72bcda09ee067654acee
这意味着在branchB上没有任何提交不在branchA上,而在branchA上有许多提交(至少是上面列出的7个)不在branchB上。实际上,所有这7个列出的提交也都没有被复制——毫不奇怪,如果左侧(branchB)没有独有的提交,那么所有独有于右侧(branchA)的提交都不可能被复制。
这意味着我们可以得到一个近似的图形,如果我们要求的话(这里的哈希值可能不正确)。
* 692d271 (branchB) commit 7
* ....... commit 6
* ....... commit 5
* ....... commit 4
* ....... commit 3
* ....... commit 2
* c5f8410 commit 1
* xxxxxxx (branchA) branch point

这是一种-可能是唯一的方式-来获取您所看到的输出。

同时:

git diff branchA branchB
git diff branchB branchA

(both produce no output at all.)

这意味着与branchA相关联的源代码树与与branchB相关联的源代码树匹配(在执行差异比较时,可能会进行任何筛选)。有许多方法可以实现这一点,很难说使用了哪些方法,但以下是一个示例:
$ git branch remember-where-we-parked-kids
$ echo new file > new-file && git add new-file
$ echo add another line >> existing-file && git add existing-file
$ git commit -m 'commit a change'
[master 643b37e] commit a change
 2 files changed, 2 insertions(+)
 create mode 100644 new-file
$ git revert --no-edit HEAD
[master 0af7c6a] Revert "commit a change"
 2 files changed, 2 deletions(-)
 delete mode 100644 new-file

第一个提交包含添加文件和修改文件的更改。第二个(还原)提交包含删除已添加的文件new-file并将旧文件existing-file恢复到刚才的状态,删除了添加的行。将当前提交与两步前的提交进行比较将不会显示任何差异,因为总共的两个提交都没有做任何事情。
在remember-where-we-parked-kids分支上使用git cherry命令,我们会发现这两个添加提交(修改和其还原)都不在“其他”分支中(该分支只比我们当前分支落后两个提交)。
$ git cherry remember-where-we-parked-kids master
+ 643b37ef242fdc35dfdd4551b42393af3eb91a85
+ 0af7c6a3cf5e49928de132c341c848be80ab84c7

以下是我们的两个提交,还原提交为0af7c6a,初始更改为643b37e。将参数反转到git-cherry中,我们得到了空值,当然git diff同样为空:

$ git cherry master remember-where-we-parked-kids 
$ git diff master remember-where-we-parked-kids
$

“没有更多的信息,我们无法确定你是如何到达现在的状态。” 但是,你所看到的输出结果是这样的。

2
这意味着branchAbranchB的内容是相同的,但由于某种原因,branchB上存在一些提交,而这些提交在branchA上不存在。
这些提交被显示出来。然而,这些提交的总和结果是相同的,因此您将看不到任何差异。即使使用git cherry branchA branchB,也不会看到任何东西,因为branchB上没有任何提交不在branchA上。

好的,我明白了。但我真正想知道的是为什么一个分支上有更多的提交而另一个分支上没有。我相信从一个分支挑选到另一个分支会解决这个问题,因为它会创建一个新的提交。 - BestPractices
git cherry 不会复制提交记录。它会列出可能使用 git cherry-pick 复制的提交记录。然而,git cherry-pick 更适用于单个特定的提交记录。要复制一堆提交记录,只需使用 git rebase 即可。在您的情况下,由于其中一个分支只是另一个分支的快进,如果您不想要合并提交记录,则最简单的方法是使用 git merge --ff-only - Joseph K. Strauss

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