How to compare changesets in Git?
Asked Answered
L

6

16

Git makes it very easy to compare differences between commits, using for instance the git commands diff and difftool. Also in TortoiseGit you just select two commits to compare them.

But is there a way to compare changesets? In other words: to see the differences between the diffs of one set of commits and the diffs of another set of commits.

This would be very handy to compare (sets of) commits which are cherry-picked or have been rebased.

Labrum answered 17/2, 2011 at 22:44 Comment(4)
This is a little snarky, but one answer is to try to never need to do this. If you do have two similar but not identical changesets, they should hopefully start from a reasonable common ancestor, so you can just diff them. And if you cherry-pick/rebase, hopefully you won't actually modify the changeset in the process, so there's nothing to diff; failing that, if you later modify the transplanted version, you should be able to just diff between the original transplant and the new one.Auscultate
It's snarky indeed. I don't need to do it often. However branches get rebased frequently (interactive + non-interactive). So, as an integrator of a very very smal team, I would like to know if the rebased branches still contain the same changeset or to see what is changed in the changeset.Labrum
The other thing, of course, is that if you're looking for a yes or no, you could simply generate the combined diff of the two changesets and diff those. Might be good enough.Auscultate
I just found https://mcmap.net/q/576328/-diff-39-ing-diffs-with-diff which lead to other ways of doing something close to what you want.Chronograph
S
15

Perhaps diff <(git show rev1) <(git show rev2) will do what you want?

Sophocles answered 18/2, 2011 at 10:6 Comment(2)
It's very good for comparing the changesets of two single commits but not for a set of them. The code above works on linux but not on git bash of msysgit. However I could make a script to compare the two changesets in a gui difftool.Labrum
Being able to do stuff like this is why I like cygwin git over msysgit.Chronograph
A
6

I think that in general to get what you want, you'll have to do some sort of merge/rebase operation in order to create something to compare with.

When you really think about it, the idea of a diff between changesets is fuzzy. I'm assuming here that you're in a situation like this:

[other history]   [ "changeset 1" ]
o - o - o - o - o ( - o - o - o - o)
 \
  (o - o - o - o - o)
  [ "changeset 2" ]

So what does it mean to compare those two? Maybe in your case, the diffs in the other history are completely disjoint from those of the two changesets, but in general, the contents of changeset 1 may depend on that other history! This means that there's no good general way for git to perform an operation like this; to do it properly, it'd have to essentially say "what would the difference between the two end commits be if I rebased?" In other words, I believe that the only reasonable definition of the diff between the changesets is the diff between the resulting end commits if they're rebased to have a common ancestor. And of course, if that's what you want, then you'll have to perform an operation in the work tree - there's no other way to muck around with diffs like this. The obvious thing to do would be to rebase, and compare the new endpoints (branches):

[other history]   [ "changeset 1" ]
o - o - o - o - o ( - o - o - o - o)
                 \
                  (o - o - o - o - o)
                  [ "changeset 2'" ]

Rebases aren't always the most fun, though, and I can think of one little way to work around this. The resulting work tree of the rebase, assuming you resolve conflicts appropriately, ought to be the same as the result of a merge:

[other history]   [ "changeset 1" ]
o - o - o - o - o ( - o - o - o - o)
 \               \
  \               ------
   \                    \
   (o - o - o - o - o) - X
    [ "changeset 2" ]

So you could perform that temporary merge, and compare the resulting commit to the end commit of the other changeset. That'll be a lot faster than doing the rebase. (Either way, you'll of course use a throwaway branch, not the real one for changeset 2.)

Auscultate answered 18/2, 2011 at 6:51 Comment(3)
The last diagram is a very good idea. As long there are no conflicts to resolveLabrum
The second diagram would be, for my team, like doing the same job as one of the other developers did.Labrum
@Paul: Part of the idea here is that if there are conflicts to resolve, they're inherently part of constructing a diff between the two changesets. Perhaps if you think of it like this: what you want is the diff between the two end commits, with all of the diffs resulting from "other history" removed. Disentangling those diffs from the diffs of changeset 1 is equivalent to resolving the conflicts.Auscultate
P
2

Here's what worked for me to compare two changesets:

git diff [base_sha_a]..[final_sha_a] > ./a.diff
git diff [base_sha_b]..[final_sha_b] > ./b.diff
diff ./a.diff ./b.diff

If the result of the diff command is empty, the changesets are the same. Otherwise you'll see the difference between the two diffs.

Permanency answered 17/12, 2016 at 14:56 Comment(1)
See also https://mcmap.net/q/576328/-diff-39-ing-diffs-with-diff/5534993Zizith
M
1

Expanding on jeff-bradberry's answer:

To compare the changesets introduced by two single commits:

diff <(git show -U0 <sha-A>) <(git show -U0 <sha-B>)

To compare the change sets introduced by two sequences of commits:

diff <(git show -U0 <sha-A>...<sha-B>) <(git show -U0 <sha-C>...<sha-D>)

Note: -U0 is to avoid comparing "context" lines (i.e. lines that have changed around your edits, but not directly by them).

Morena answered 27/5, 2020 at 5:36 Comment(0)
Y
0

Starting 2.19 we have git radge-diff. It is exactly for that.

Younker answered 16/9, 2022 at 16:51 Comment(1)
Note: git range-diff will output a list of commits. It does not show the differences in the content. I may not be what you are looking for. 🤷 The OP is not clear about that.Zizith
H
-2
git diff end_rev_1...end_rev_2

Taken from: http://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html

A similar notation r1...r2 is called symmetric difference of r1 and r2 and is defined as r1 r2 --not $(git merge-base --all r1 r2). It is the set of commits that are reachable from either one of r1 or r2 but not from both.

And from git diff help:

git diff [--options] <commit>...<commit> [--] [<path>...]
   This form is to view the changes on the branch containing and up to the second <commit>, starting at a
   common ancestor of both <commit>. "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B".
   You can omit any one of <commit>, which has the same effect as using HEAD instead.

Does that work for you?

Honorine answered 17/2, 2011 at 23:0 Comment(2)
I don't think this is what the OP wants. Look at what it's equivalent to - it doesn't actually have anything to do with the changes on A; it just uses it as a way to find the starting point for the diff.Auscultate
It's indeed not what I need. This answers how to compare the differences of the project contents between two commits (or revisions). I would like to know how one (or more) commit(s) change the contents (=changeset) and compare that with the changeset of one (or more) other commit(s).Labrum

© 2022 - 2024 — McMap. All rights reserved.