void.pointer
void.pointer

Reputation: 26365

triple-dot notation for git diff works strangely

Suppose I have the following branch structure:

            E -- F (topic)
           /
A -- B -- C -- D (master)

I have tried the following:

git diff master..topic

and

git diff master...topic

According to the gitrevisions documentation, the double-dot notation is supposed to include (in this case) only revisions in the topic branch.

The way I visualize this is that when you use the master..topic notation, think of moving from master to topic like moving a board piece in a board game. As you move to each node (commit) you only include the commits that involve moving the piece in a forward direction. Forward here is towards the tip of topic, which means we include commits E and F.

Triple dot, in this case, is supposed to include commits in both branches. So this will be commits F, E, and D.

I expect the FIRST git diff above to show me commits E and F, but instead it shows me E, F, D (which should be triple-dot based on the rules above). The SECOND git diff shows me commits E and F when I expect it to show me E, F, G. Why are these behaving completely opposite? I understand that the git diff documentation clearly states in the examples section that the triple-dot notation behaves as expected, but I suppose when you look at how git log works and also the descriptions in the git revisions documentation, git diff seems inconsistent and doesn't follow normal patterns.

Upvotes: 3

Views: 1220

Answers (2)

mockinterface
mockinterface

Reputation: 14860

For git diff you should be looking at the git diff documentation instead of the revisions specs documentation.

git diff [options] blob blob
    This form is to view the differences between the raw contents
    of two blob objects.
git diff [--options] commit..commit [--] [path...]
    This is synonymous to the previous form. If  on one side
    is omitted, it will have the same effect as using HEAD instead.

When you invoke git diff master..topic it is expected to get the outcome of the raw difference between the raw content of the commits pointed by master and topic, respectively. Thus git correctly shows you the content difference between (E,F) and (D).


The simple interpretation for git diff master...topic is all the changes that happened on topic since it was branched off master ignoring changes on the latter (ie., the difference for topic starting from the merge-base of the two), and in this case the shown difference would be (E,F) without (D).

Upvotes: 2

torek
torek

Reputation: 488619

[Edit to fix brain-o]

The double- and triple-dot notation has that meaning for git rev-list (and all the commands that use it, which is quite a few of them), but not for git diff.

As a special-case hack, when you run git diff and use the double-dot notation, it simply diffs the commit named by the left-hand name, against the commit named by the right-hand name. So git diff x..y is really just git diff x y. Meanwhile, git diff x...y is a different special case, that takes the merge-base of x and y as the starting point: it means git diff $(git merge-base x y) y.

In short, you're right: git diff does not follow the normal patterns. (There is a good excuse, as it were, in that diffs are done pair-wise, rather than across a series of commits. But git knows how to do combined diffs for merge commits, so it's not a great excuse. :-) )

Upvotes: 1

Related Questions