2

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.

void.pointer
  • 24,859
  • 31
  • 132
  • 243
  • Documentation says "However, "diff" is about comparing two _endpoints_, not ranges, and the range notations (".." and "...") do not mean a range as defined in the "SPECIFYING RANGES" section in gitrevisions(7)." What other answer do you expect? – Alexey Ten Feb 05 '14 at 19:24
  • @alexeyten A range can be treated as a set of endpoints, just ignore the middle nodes. This is poor implementation of the diff component, IMHO. `git diff` already supports the range syntax to diff a single branch to its base commit, but it is doing it wrong. So the argument of "it works with endpoints" doesn't hold much water. – void.pointer Feb 06 '14 at 20:53
  • Perhaps worth mentioning how you can achieve the ... diff with the current working tree: http://stackoverflow.com/questions/23975995/git-diff-branch-against-working-tree-not-including-merges – Andy Hayden Jun 01 '14 at 18:28

2 Answers2

2

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

mockinterface
  • 14,452
  • 5
  • 28
  • 49
  • You are right and I already knew this, I guess I just wanted someone to say "You're right, this aspect of diff is confusing and they should fix it". – void.pointer Feb 06 '14 at 20:55
  • @RobertDailey Good, then you can affirm the affirmation by accepting the answer! :) – mockinterface Feb 07 '14 at 08:25
  • I wanted to give the question some time to get a few more views before I accepted an answer :-), but not much more to say on the matter anyway! Thanks again. – void.pointer Feb 07 '14 at 14:16
  • Great, this came up when trying to do this with the current working tree, which you can't do with ... (I don't think) Perhaps worth mentioning the ... notations with the current working tree: http://stackoverflow.com/questions/23975995/git-diff-branch-against-working-tree-not-including-merges – Andy Hayden Jun 01 '14 at 18:28
1

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

torek
  • 448,244
  • 59
  • 642
  • 775
  • Do you mean that `git diff x y` is the same as `git diff x..y`? because `git diff x y` would include changes that may go past the base of branch `y` (commits made on `x` after branch `y` was created). – void.pointer Feb 05 '14 at 15:56
  • Manual page clearly states difference between two-dot and three-dot notations https://www.kernel.org/pub/software/scm/git/docs/git-diff.html – Alexey Ten Feb 05 '14 at 19:18
  • @RobertDailey: oops, yes, x...y is special-cased to be the merge-base. – torek Feb 05 '14 at 19:36