TL;DR: you want git rev-list --left-right --count A...B
. Note three dots, not two.
The two-dot notation means1 commits reachable from B
, minus any commits reachable from A
. Suppose there are 17 such commits because the revision history looks like this:
...--o--o--o <-- A
\
o--o--o--...--o <-- B (17 commits in total, 13 not shown here)
All commits on the top row are reachable from A
so they get subtracted away from the set of commits reachable from B
(both rows). That leaves the 17 that you get counted.
Swapping the order means commits reachable from A
, minus any commits reachable from B
. Since all commits are reachable from B
, we subtract them from the set of commits reachable from A
, leaving no commits at all. The count is therefore zero.
The three-dot notation A...B
means2 commits reachable from either A
or B
, minus all commits reachable from both A
and B
. In the diagram above, there are 17 commits reachable from B
but not A
, and zero commits reachable from A
and not B
. Using --left-right
splits them into their sub-groups; using --count
counts them; putting both together gets you the two numbers, and the two numbers will take the left or right position depending on whether you use A...B
or B...A
.
The three-dot notation is more useful in a graph that looks like:
o--o <-- A
/
...--*
\
o--o--o <-- B
Here there are two commits reachable from A
but not B
, and three commits reachable from B
but not A
. All the middle-row commits *
and earlier are reachable from both tips and hence excluded by the three-dot notation.
1For git diff
, the two and three dot notations mean something very different. The diff commands mostly demand just two commits, and A..B
or A...B
quite often mean many commits—more than the two that git diff
likes—so git diff A..B
just means: use A
as the left side and B
as the right, which is exactly the same thing as git diff A B
. That's not really all that useful, since you could have replaced the two dots with a space yourself, but that is what it means.
2In git diff
, the three-dot syntax takes on a new and very different (and useful!) meaning. Instead of comparing commits A
and B
, the A...B
notation means: Find the excluded commit in the middle—this is, more or less, the merge base—and use that as the left side. Use B
as the right side. For the last case illustrated above, the excluded commit in the middle is commit *
, which really is the merge base. So git diff A...B
means diff commit *
vs commit B
, while git diff B...A
means diff commit *
vs commit A
.
Sidebar: an easy way to think about this
For those who are visually-oriented, imagine you have a printed version of the graph and two different colored highlighting markers, red and green. You take the graph, such as:
o--o <-- A
/
...--*
\
o--o--o <-- B
You take your red highlighting marker and mark the commit to which A
points. Then, follow the backwards connectors from that commit to its parent(s). Mark those red too. Keep moving backwards until everything you can get to this way—by moving backwards, through all parent commits at any merges—is marked red.
Then, take your green highlighting marker and mark the commit to which B
points. Follow this one backwards to its parent(s), and mark those green. Keep marking green until everything you can get to this way is marked green.
Any commits with only green highlighting are included. Any commits with red or both highlighting are excluded. What you have really done here is set subtraction, of the two sets of reachable commits, but it's easy to think about.