Reputation: 12876
I have two branches: branchA, branchB
The following returns no output (including no differences, at least for the git diff
command):
git cherry branchA branchB
git diff branchA branchB
git diff branchB branchA
When I run this however:
git cherry branchB branchA
I get a list of commit ids all with a plus sign in front of them:
e.g.
+ c5f84105c242939a9d18fb9d6355534a80735277
+ 41acd0a40bfeaf3d68185a540c131838651cd889
+ 4859fd89c5dafeed6a68f0881ea6ad081a53fd68
+ 7226c9e5acf5a9d2d33b6aef3e5abf9b040f0b76
+ 4fc3206508d6ce7a19477e4c006608c78bb28801
+ 8816c66ed72da762b9b34858eec5b52a16d0ea99
+ 692d271ab07d4b92e54e72bcda09ee067654acee
Can someone please explain what this implies? Looking to understand why git diff shows no differences but git cherry shows differences.
Upvotes: 5
Views: 5106
Reputation: 3791
git-diff(1) compares the contents of two branches. git-cherry(1) reports commits that are not in some other branches and (out of those) which of them have a patch-id equivalent [1] in the other branch.
You could create a repository where two branches have the same tree (the empty tree for example) but not the same commits since one of the other branches did a commit and then an immediate revert:
$ d=$(mktemp -d)
$ cd $d
$ # branch is `main`
$ git init
$ git commit --allow-empty -minit
$ git checkout -b other
$ echo 'start new project' >README.md
$ git add README.md
$ git commit -mReadme
$ git revert --no-edit HEAD
$ git diff main other
[empty output]
$ git cherry main other
+ 028db15895414e94f230618cb00a52036b185d50
+ f0e5528c570e7db4cb6012c56e2c9e4969d2e9c1
Upvotes: 0
Reputation: 488203
I'm not at all sure where your confusion comes from, especially since git diff
and git cherry
do very different things.
It would probably help (as is almost always true in Git) to draw the commit graph, or at least the relevant part, e.g., run git log --graph --oneline --all --decorate
, or snip some window image from gitk
, or (this is just the documentation's suggestion from below, modified to match your branch names, but it would show just what we need):
git log --oneline --graph --boundary branchA...branchB
(In some cases leaving out --boundary
can make this significantly clearer, when there are very many commits that lie on the boundary of the symmetric difference, but for most simple cases it just adds the merge base commit and thus aids in reading the result.)
Now, let's also take a look at the git cherry documentation, which has a nice example of how we use the three-dot symmetric difference notation to understand the output of 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
Here, commit 1234567
is the one that --boundary
included. Normally the three-dot notation would have selected only the origin/master
(left side) commits like 7654321
, cccc1111
, and aaaa111
for the left half of the ...
, and the master
(right side) commits like cccc000
, bbbb000
, and aaaa000
commits for the right half. Adding --boundary
adds the shared commit that, in effect, separates these left and right halves.
Look at what our maintainer guy upstream did: he accepted our commit A
and our commit C
, copying them change-for-change into his master
which we see in our origin/master
. He did not accept our commit B
, or at least, not change-for-change (we can't tell from this, nor from git cherry
, if he has taken some alternate version of our change).
Now look at the sample output from running 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
This shows us all three commits on the right side (topic
), while not showing us any of the commits on the left side (origin/master
), of our log [flags] origin/master...topic
listing.
For the commits it does show—those exclusively on the right—it marks each one with -
(taken) or +
(not taken).
We don't have a graph fragment, though, so let's work with what we do have at the moment.
git cherry branchA branchB
[is empty, but]
git cherry branchB branchA
(includes at least)
+ c5f84105c242939a9d18fb9d6355534a80735277 + 41acd0a40bfeaf3d68185a540c131838651cd889 + 4859fd89c5dafeed6a68f0881ea6ad081a53fd68 + 7226c9e5acf5a9d2d33b6aef3e5abf9b040f0b76 + 4fc3206508d6ce7a19477e4c006608c78bb28801 + 8816c66ed72da762b9b34858eec5b52a16d0ea99 + 692d271ab07d4b92e54e72bcda09ee067654acee
This mean that there are no commits on branchB that are not also on branchA, while there are many (at least the 7 listed above) commits on branchA that not on branchB. In fact, all of those 7 listed are all not-copied as well—not surprising, none of the exclusive-to-right-side branchA
commits could possibly have been copied, if there are no exlusive-to-left-side (branchB
) commits at all.
This means we can draw an approximation of the graph we would have gotten, if we had asked for one (I may have the wrong abbreviated hashes here):
* 692d271 (branchB) commit 7
* ....... commit 6
* ....... commit 5
* ....... commit 4
* ....... commit 3
* ....... commit 2
* c5f8410 commit 1
* xxxxxxx (branchA) branch point
This is a way—probably the only way—to get the output you saw.
Meanwhile:
git diff branchA branchB git diff branchB branchA
(both produce no output at all.)
This just means that the source tree attached to branchA
matches the source tree attached to branchB
(after, perhaps, any filtering you selected when doing the diff). There are a bunch of ways to achieve that and it is hard to say which one(s) may have been used, but here is an example of what would do that:
$ 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
The first commit contains a change that adds a file and modifies a file. The second (revert) commit contains a change that removes the added file new-file
and puts the old file existing-file
back the way it was just a moment ago, removing the added line. Comparing the current commit to the commit made two steps ago will show no differences, since the sum total of the two commits was to do nothing after all.
Using git cherry
on branch remember-where-we-parked-kids
, we would see that neither of the two added commits (the modification and its revert) are in the "other" branch (which is just two commits behind from where we are now):
$ git cherry remember-where-we-parked-kids master
+ 643b37ef242fdc35dfdd4551b42393af3eb91a85
+ 0af7c6a3cf5e49928de132c341c848be80ab84c7
(these are our two commits, the revert, 0af7c6a
, and the initial change, 643b37e
). Reversing the arguments to git-cherry
, we get nothing, and of course the git diff
is equally empty:
$ git cherry master remember-where-we-parked-kids
$ git diff master remember-where-we-parked-kids
$
It's not possible to say how you got where you are now without more information, but this is what the output you have seen means.
Upvotes: 3
Reputation: 589
Git diff shows no output as the files in both branches are identical in content. However the commit ID (SHA string) might be different.
git cherry branchA branxhB is giving no output as all the commits (SHA and not file contents) in branch B is present in branch A. However vice versa is not true. There are some commits in branch A that are not in branch B and hence the output of git cherry branchB branchA. This is very well explained with example here. http://jafrog.com/2012/03/22/git-cherry.html
Upvotes: 4
Reputation: 4903
It means that the content of branchA
and branchB
are the same, but for some reason there are commits on branchB that are not on branchA.
These commits are being displayed. However, the sum total of these commits results in the same content, so you will not see any diff. You will not see anything with git cherry branchA branchB
either, because there are no commits on branchB
that are not on branchA
.
Upvotes: 2