I am trying to compare changes that were made on two different branches that forked from master at two different commits. So, I do not want to see the changes that were made
The revision parsing code for git diff
is overly permissive, and then winds up doing the wrong thing with multiple arguments. In some cases it mis-interprets its arguments if you give it more than two commit IDs and at least one of them is negated (as you are doing). In particular, it winds up treating the (positive-ref, positive-ref, negative-ref) triple as if it were the three-dot syntax.
Several weeks ago, I submitted a Git fix specifically for this, which (as usual) has been ignored (sigh). Even with this fix, though, you can't get what you want. Except for the even-more-special case of combined diffs—which still are not what you want—you can only have Git compare at most two existing trees already stored in the repository:
I am trying to compare changes that were made on two different branches that forked from master at two different commits. So, I do not want to see the changes that were made on master in-between the two branches.
In other words, you have a commit graph that goes something like this:
a--a--A <-- feature-A
/
...--o--*--o--o-... <-- master
\
b--B <-- feature-B
and you want to compare the tip-most commit of feature-A
—i.e., commit A
—to what you would get if you took the two commits that are exclusively on feature-B
(commits b
and B
) and applied them to the commit I marked with a *
, i.e., the point where feature-A
branched off from master
.
You can quite easily have Git compare the tree for commit A
vs the tree for commit B
. This is what git diff feature-A feature-B
and git diff feature-A..feature-B
do. But this is not what you want.
To get a diff between the tree for commit A
and a (currently hypothetical) tree B'
you must create a temporary branch,1 and then cherry-pick the two feature-B
-only commits onto *
:
a--a--A <-- feature-A
/
...--o--*--o--o-... <-- master
\ \
\ b--B <-- feature-B
\
b'-B' <-- temporary branch
Now you really do have a commit B'
with the tree that you get if you "take away" the two intermediate master
commits, and now you can compare the tree for A
against this new commit's tree.
1It is technically possible to do all this without a temporary branch, by constructing the hypothetical tree B'
in the work-tree, without committing, using git cherry-pick -n
, rather than as a series of commits on a temporary branch using git cherry-pick
. But commits in Git, including temporary ones on a temporary branch, are fast enough and cheap enough that this does not buy you much—and if some of the cherry-pick steps require resolving merge conflicts, it just makes everything that much more difficult.