开发者

How to compare changesets in Git?

Git makes it very easy to compare differences between commits, using for instance the git commands diff and dif开发者_如何学Cftool. 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.


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


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.)


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.


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).


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


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?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜