Some Git commands take commit ranges and one valid syntax is to separate two commit names with two dots ..
, and another syntax uses three dots ...
.
What are the differences between the two?
Some Git commands take commit ranges and one valid syntax is to separate two commit names with two dots ..
, and another syntax uses three dots ...
.
What are the differences between the two?
It depends on whether you're using a log
command or a diff
command. In the log
case, it's in the man git-rev-parse
documentation:
To exclude commits reachable from a commit, a prefix ^ notation is used. E.g. ^r1 r2 means commits reachable from r2 but exclude the ones reachable from r1.
This set operation appears so often that there is a shorthand for it. When you have two commits r1 and r2 (named according to the syntax explained in SPECIFYING REVISIONS above), you can ask for commits that are reachable from r2 excluding those that are reachable from r1 by "^r1 r2" and it can be written as "r1..r2".
A similar notation "r1...r2" is called symmetric difference of r1 and r2 and is defined as "r1 r2 --not $(git merge-base --all r1 r2)". It is the set of commits that are reachable from either one of r1 or r2 but not from both.
Which basically means that you'll get all commits that are in either of the two branches, but not in both.
In the diff
case, it's in the man git-diff
documentation:
git diff [--options] <commit>...<commit> [--] [<path>...] This form is to view the changes on the branch containing and up to the second <commit>, starting at a common ancestor of both <commit>. "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B". You can omit any one of <commit>, which has the same effect as using HEAD instead.
Which is a bit fuzzy. Basically it means it shows only the differences in that branch compared to another branch: it looks for the last common commit with the first committish you gave it, and then diffs the second committish to that. It's an easy way to see what changes are made in that branch, compared to this branch, without taking notice of changes in this branch only.
The ..
is somewhat simpler: In the git-diff
case, it's the same as a git diff A B
and just diffs A against B. In the log
case, it shows all commits that are in B but not in A.
..
and ...
is exactly swapped for log and diff: log A..B
is changes from merge base to B which is what diff A...B
does –
Teressaterete git diff
. –
Jobi A...B
== A..B + B..A
? –
Reticule git log
this is absolutely yes –
Gloriane git diff
it's the opposite! git diff A..B
== git diff A...B + git diff B...A
! –
Lathrope When you're using commit ranges like ..
and ...
with git log
, the difference between them is that, for branches A and B,
git log A..B
will show you all of the commits that B has that A doesn't have, while
git log A...B
will show you both the commits that A has and that B doesn't have, and the commits that B has that A doesn't have, or in other words, it will filter out all of the commits that both A and B share, thus only showing the commits that they don't both share.
Here is a visual representation of git log A..B
. The commits that branch B contains that don't exist in A is what is returned by the commit range, and is highlighted in red in the Venn diagram, and circled in blue in the commit tree:
These are the diagrams for git log A...B
. Notice that the commits that are shared by both branches are not returned by the command:
...
More UsefulYou can make the triple-dot commit range ...
more useful in a log command by using the --left-right
option to show which commits belong to which branch:
$ git log --oneline --decorate --left-right --graph master...origin/master
< 1794bee (HEAD, master) Derp some more
> 6e6ce69 (origin/master, origin/HEAD) Add hello.txt
In the above output, you'll see the commits that belong to master
are prefixed with <
, while commits that belong to origin/master
are prefixed with >
.
Someday I might add my own explanation for how the commit ranges work with git diff
, but for now, you might want to check out What are the differences between double-dot ".." and triple-dot "..." in Git diff commit ranges?.
git diff
, though I'm not sure if that answer will be clear for most people. As I commented on the question above, this question deals with git diff
specifically. –
Aforethought git diff A..B
shows all commits that they don't have each other; and git diff A...B
shows only B has according to shared ancestor.. git version 2.18.0 –
Expulsion git log
behaviour doesn't shed more light, but confusion. –
Lavinia diff A...B
by default, which is the same as log A..B
, which means ... I don't quite follow haha. Can you someone help reconcile this SO answer with this explanation from the GitHub discussion link? Would appreciate any help. –
Occident ..
and ...
behave differently in git diff
and git log
. See the diagram in this answer for clarification - https://mcmap.net/q/11932/-what-are-the-differences-between-double-dot-quot-quot-and-triple-dot-quot-quot-in-git-diff-commit-ranges –
Amero It depends on whether you're using a log
command or a diff
command. In the log
case, it's in the man git-rev-parse
documentation:
To exclude commits reachable from a commit, a prefix ^ notation is used. E.g. ^r1 r2 means commits reachable from r2 but exclude the ones reachable from r1.
This set operation appears so often that there is a shorthand for it. When you have two commits r1 and r2 (named according to the syntax explained in SPECIFYING REVISIONS above), you can ask for commits that are reachable from r2 excluding those that are reachable from r1 by "^r1 r2" and it can be written as "r1..r2".
A similar notation "r1...r2" is called symmetric difference of r1 and r2 and is defined as "r1 r2 --not $(git merge-base --all r1 r2)". It is the set of commits that are reachable from either one of r1 or r2 but not from both.
Which basically means that you'll get all commits that are in either of the two branches, but not in both.
In the diff
case, it's in the man git-diff
documentation:
git diff [--options] <commit>...<commit> [--] [<path>...] This form is to view the changes on the branch containing and up to the second <commit>, starting at a common ancestor of both <commit>. "git diff A...B" is equivalent to "git diff $(git-merge-base A B) B". You can omit any one of <commit>, which has the same effect as using HEAD instead.
Which is a bit fuzzy. Basically it means it shows only the differences in that branch compared to another branch: it looks for the last common commit with the first committish you gave it, and then diffs the second committish to that. It's an easy way to see what changes are made in that branch, compared to this branch, without taking notice of changes in this branch only.
The ..
is somewhat simpler: In the git-diff
case, it's the same as a git diff A B
and just diffs A against B. In the log
case, it shows all commits that are in B but not in A.
..
and ...
is exactly swapped for log and diff: log A..B
is changes from merge base to B which is what diff A...B
does –
Teressaterete git diff
. –
Jobi A...B
== A..B + B..A
? –
Reticule git log
this is absolutely yes –
Gloriane git diff
it's the opposite! git diff A..B
== git diff A...B + git diff B...A
! –
Lathrope I think the biggest source of confusion about two dots versus three dots is because when used with git diff
it's sort of the opposite of when used with git log
.
Please see the other answers, the actual documentation, or numerous blog posts for the exact details, but I find these simple statements to work well for conveying the right idea:
git log A..B # Show me commits only on B.
git log A...B # Show me commits only on A or only on B.
git diff A..B # Show me changes only on A or only on B.
git diff A...B # Show me changes only on B.
This is a bit confusing = So here is a how it is actually for this flow
A---B---C topic
/
D---E---F---G main
https://github.com/alexcpn/gitdiffs/pull/2/commits https://github.com/alexcpn/gitdiffs/pull/1/commits
Git Log Behaviour
1 | > git log --oneline --graph topic...main * 9411a8b (HEAD -> main) G * 3a567aa F * aad429f (topic) C * 6b1eb5a B * d65c129 A |
topic D E A B C |
main D E F G |
In topic and main, but not in both |
2 | git log --oneline --graph main...topic * 9411a8b (HEAD -> main) G * 3a567aa F * aad429f (topic) C * 6b1eb5a B * d65c129 A |
topic D E A B C |
main D E F G |
Same as above |
3 | git log --oneline --graph topic..main * 9411a8b (HEAD -> main) G * 3a567aa F |
topic D E A B C |
main D E F G |
In main,but not in topic |
4 | git log --oneline --graph main..topic * aad429f (topic) C * 6b1eb5a B * d65c129 A |
topic D E A B C |
main D E F G |
In topic, but not in main |
Git Diff behaviour
1 | git diff topic..main D E -A -B -C +F +G |
topic D E A B C |
main D E F G |
what's in main whats not in main compared to topic |
2 | git diff main..topic D E -F -G +A +B +C |
topic D E A B C |
main D E F G |
whats in topic whats not in topic compared to main |
3 | git diff main...topic D E (you may get newline here) +A +B +C |
topic D E A B C |
main D E F G |
In topic,but not in main |
4 | git diff topic...main D E +F +G |
topic D E A B C |
main D E F G |
In main, but not in topic |
The '...' syntax is shorthand for "diff between two branches, starting with the common ancestor". From the official Git book:
git diff master...contrib
is equivelent to:
$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db
© 2022 - 2024 — McMap. All rights reserved.