10

I rebased a fairly old topic branch onto master. Since there were quite a few conflicts during the rebase, I'd like to compare the old topic branch with the rebased one, to make sure I didn't accidentally remove or screw up any of the changes on topic. The closest I've gotten to this is diffing the results of git diff master...topic and git diff master...topic-rebased. This kind of works, but there's a lot of noise in the final diff from changes in the context code, line numbers, commit hashes, etc, in addition to it not being a very robust solution. Is there an easier way to do this?

Ryan
  • 496
  • 6
  • 13
  • Depending on the complexity verses importance, you could try rebasing it again and compare that result to `topic-rebased`... (This is working on the assumption that you'll be more careful at different places the second time around.) Otherwise, the -U option on `git diff` can cut back the context and you could try grepping out the hunk headers containing line numbers and blob hashes. – antak Feb 16 '12 at 07:58
  • An interesting alternative is to rebase it (e.g. `master..topic-rebased`) back onto *merge-base* (or where ever `topic` came from) and compare (diff) this to `topic`. This would act like a mathematical proof and any deltas you see here should be those of significance. The rebasing here could be done with `cherry-pick` or `rebase upstream topic~0 --onto new_base`. I don't know your level of knowledge but "rebasing back" in this case shouldn't involve hosing your current branches because I'm expecting it'll be done in a detached state or in a throw-away branch. – antak Feb 16 '12 at 15:48
  • rebasing back won't work as the other conflicts will result. – Adam Dymitruk Feb 16 '12 at 20:49
  • Other conflicts? Isn't whether or not it works for you a function of the repository and how much time you're willing to spend? I can imaging getting at minimum the *same conflicts* in reverse, but your comment seems to show insight about the repo that the OP hasn't shared with us. Even then, the whole idea is to resolve your "other conflicts", because for this pure verification exercise, each one that crops up hints on how different your series is becoming. – antak Feb 17 '12 at 00:50
  • This is a set of conflicts that are once removed and would not have been there in the original. Diminishing territories even if you save them with rerere. – Adam Dymitruk Feb 20 '12 at 17:12
  • @AdamDymitruk I have a suspicion that yours and my idea of what the OP wants is slightly off. Specifically, I felt your answer below merely reworded what the OP said he was doing, and doesn't address the actual problem of removing the excess output thereafter. I couldn't make sense of your last comment above in our current context. However, I do use the reverse rebasing method quite often to get a bearing on how I went in the other direction. Maybe it doesn't work for you or in the general case, I dunno. I just throught it was worthwhile because it saves me time nonetheless. – antak Feb 21 '12 at 11:54
  • 2
    Check out `git range-diff` with Git 2.19 (Q3 2018). See "[Git diff - two disjoint revision ranges](https://stackoverflow.com/a/51956694/6309)", and "[Git diff branch before and after rebase ignoring changes in master](https://stackoverflow.com/a/51956712/6309)". – VonC Aug 21 '18 at 21:10

3 Answers3

5

I was struggling with this same issue and came up with similar ideas as Ryan and Adam Dymitruk and found them not very satisfactory: Comparing the final diff is tricky and also doesn't show you where the "error" was introduced if you find it.

My current rebase workflow includes comparing each rebased commit with original one, so I can spot and correct potential errors as they appear and don't have to redo the rebase. I'm using the following pair of git alias to facilitate this:

rc = !git diff -w $(cat .git/rebase-merge/stopped-sha) > .git/rebase-merge/current-diff
rd = !git diff -w $(cat .git/rebase-merge/stopped-sha) | diff --suppress-common-lines .git/rebase-merge/current-diff - | cut -b 1-2 --complement | less

git rc stores the diff between HEAD the latest revision from the branch that is being rebased. After replaying the following commit, git rd compares this stored diff to the diff between the new HEAD and the next commit on the branch being rebased. Therefore this shows you only the difference ("error") introduces by replaying this last commit.

After inspecting the diff, call git rc to update the stored diff and continue the rebase.

Instead of manually calling git rc and git rd you could even add them to your git-rebase-todo so they're called automatically after each commit is replayed.

kynan
  • 13,235
  • 6
  • 79
  • 81
5

You probably would want to diff the effective changes (patches) produced by each:

diff <(git log master..topic -p) <(git log master..old-place-of-topic -p)

This would effectively remove any changes introduced in master.

Adam Dymitruk
  • 124,556
  • 26
  • 146
  • 141
  • Correct me if I'm wrong, but this would also show all of the changes from `git merge-base master topic` to `git merge-base master topic-rebased`, which I don't want. I only want to view changes specific to the topic branch. Also, no need for reflog, I have both topic and topic-rebased still available. – Ryan Feb 15 '12 at 23:12
  • I appreciate the response, but this has the exact same result and issues (assuming you meant `master...old-place-of-topic`) as what I currently do (mentioned in the question). – Ryan Feb 16 '12 at 01:33
  • It shouldn't. "..." takes all diffs up common ancestor. This would include anything on master that was committed after the topic branch was created originally. – Adam Dymitruk Feb 16 '12 at 01:42
  • to see what was excluded: `diff $(git merge-base master old-topic)..$(git merge-base master topic)` – Adam Dymitruk Feb 16 '12 at 01:48
  • With your answer, `git diff master..old-place-of-topic` will have, like you said, everything on master since old-place-of-topic was branched. `git diff master..topic` won't (topic already has the latest from master on it), so all of those changes will be polluting the final diff. – Ryan Feb 16 '12 at 02:08
  • These all do pretty much the same thing. I guess what I'm looking for is something that doesn't involving diffing diffs. – Ryan Feb 16 '12 at 05:57
  • I don't think you have an option. Diffing the effective patch or set of patches is what you need to do to see differences introduced by conflict resolutions. – Adam Dymitruk Feb 16 '12 at 20:48
  • Wow! This is so unreadable, it doesn't even squash subsequent changes! It is even worse than if I'd just print all commit changes, next manually open every file and compare it, because the diffs ends up too messed up to be line by line. – Hi-Angel Sep 30 '16 at 13:23
0

If you don't care about the commit history from your topic branch you could redo the rebase and add the --squash flag. This will give you a single commit on top of your master branch where you can and go through the changed files file by file. I would also add the flag --no-commit to the rebase so that I could review the changes prior to committing the git rebase.

git checkout master
git rebase --squash --no-commit topic
//review changes with your favourite git tool
git commit

If you don't want to redo the rebase an external diff tools like KDiff3 might help you.

MikaelHalen
  • 5,772
  • 1
  • 18
  • 16