- Let's say we have two users (
schacon
andjessica
) both having write access to the same GitHub repo
[user@pro13 schacon (master)]$ git log --oneline --all
* 6c4e96c (HEAD -> master, origin/master, origin/HEAD) Initial commit
[user@pro13 schacon (master)]$ git remote -v
origin https://github.com/txxxx-xx/xxx.git (fetch)
origin https://github.com/txxxx-xx/xxx.git (push)
[user@pro13 jessica (master)]$ git log --oneline --all
* 6c4e96c (HEAD -> master, origin/master, origin/HEAD) Initial commit
[user@pro13 jessica (master)]$ git remote -v
origin https://github.com/txxxx-xx/xxx.git (fetch)
origin https://github.com/txxxx-xx/xxx.git (push)
jessica
creates new branch, makes and commits changes, and pushes the branch toorigin
[user@pro13 jessica (master)]$ git checkout -b jessica/featureC master
Switched to a new branch 'jessica/featureC'
[user@pro13 jessica (jessica/featureC)]$ vi featureC.txt
[user@pro13 jessica (jessica/featureC ✗)]$ git add featureC.txt
[user@pro13 jessica (jessica/featureC ✗)]$ git commit -m featureC-1
[jessica/featureC 9179f6b] featureC-1
1 file changed, 1 insertion(+)
create mode 100644 featureC.txt
[user@pro13 jessica (jessica/featureC)]$ vi featureC.txt
[user@pro13 jessica (jessica/featureC ✗)]$ git add featureC.txt
[user@pro13 jessica (jessica/featureC ✗)]$ git commit -m featureC-2
[jessica/featureC e7277bf] featureC-2
1 file changed, 1 insertion(+)
[user@pro13 jessica (jessica/featureC)]$ git push origin jessica/featureC
Enumerating objects: 7, done.
Counting objects: 100% (7/7), done.
Delta compression using up to 4 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 544 bytes | 181.00 KiB/s, done.
Total 6 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: Create a pull request for 'jessica/featureC' on GitHub by visiting:
remote: https://github.com/txxxx-xx/xxx/pull/new/jessica/featureC
remote:
To https://github.com/txxxx-xx/xxx.git
* [new branch] jessica/featureC -> jessica/featureC
[user@pro13 jessica (jessica/featureC)]$ git co master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
schacon
fetchesorigin
, creates local branch based on the remote one pushed byjessica
, and checks it out
[user@pro13 schacon (master)]$ git br -avv
* master 6c4e96c [origin/master] Initial commit
remotes/origin/HEAD -> origin/master
remotes/origin/master 6c4e96c Initial commit
[user@pro13 schacon (master)]$ git fetch origin
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0
Unpacking objects: 100% (6/6), 524 bytes | 87.00 KiB/s, done.
From https://github.com/txxxx-xx/xxx
* [new branch] jessica/featureC -> origin/jessica/featureC
[user@pro13 schacon (master)]$ git br -avv
* master 6c4e96c [origin/master] Initial commit
remotes/origin/HEAD -> origin/master
remotes/origin/jessica/featureC e7277bf featureC-2
remotes/origin/master 6c4e96c Initial commit
[user@pro13 schacon (master)]$ git checkout -b featureC origin/jessica/featureC
Branch 'featureC' set up to track remote branch 'jessica/featureC' from 'origin'.
Switched to a new branch 'featureC'
[user@pro13 schacon (featureC)]$ git br -avv
* featureC e7277bf [origin/jessica/featureC] featureC-2
master 6c4e96c [origin/master] Initial commit
remotes/origin/HEAD -> origin/master
remotes/origin/jessica/featureC e7277bf featureC-2
remotes/origin/master 6c4e96c Initial commit
- Let's consider different ways for
schacon
to see what will be introduced in itsmaster
branch if thefeatureC
branch be merged into it
[user@pro13 schacon (featureC)]$ git log --oneline --all # full log
* e7277bf (HEAD -> featureC, origin/jessica/featureC) featureC-2
* 9179f6b featureC-1
* 6c4e96c (origin/master, origin/HEAD, master) Initial commit
- See all the commits in the
featureC
branch (including ones the branch was build on) with<rev>
range notation (seeman gitrevisions
)
[user@pro13 schacon (featureC)]$ git log --oneline featureC
e7277bf (HEAD -> featureC, origin/jessica/featureC) featureC-2
9179f6b featureC-1
6c4e96c (origin/master, origin/HEAD, master) Initial commit
- Exclude commits in the
master
branch with--not <branch>
flag
[user@pro13 schacon (featureC)]$ git log --oneline featureC --not master
e7277bf (HEAD -> featureC, origin/jessica/featureC) featureC-2
9179f6b featureC-1
- Exclude commits in the
master
branch with<rev1>..<rev2>
range notation (seeman gitrevisions
)
[user@pro13 schacon (featureC)]$ git log --oneline master..featureC
e7277bf (HEAD -> featureC, origin/jessica/featureC) featureC-2
9179f6b featureC-1
- Show commits limited by triple-dot range notation (
<rev1>...<rev2>
), which here has the same result as the above<rev1>..<rev2>
range. Seeman gitrevisions
for the differences in meanings for triple-dot syntax applied as 'range' forgit log
commands and as 'two endpoints' forgit diff
commands
[user@pro13 schacon (master)]$ git log --oneline master...featureC
e7277bf (origin/jessica/featureC, featureC) featureC-2
9179f6b featureC-1
‼️ Incorrect Way‼️ - Let's try to use
git diff
to show a full diff of what would happen if we were to merge topic branch (featureC
) withmaster
branch (seeman git-diff
) - What happen here are
- We checkout to the branch
featureC
- We view the changes we have in branch
featureC
working tree relative to the named commit (commit wheremaster
branch points to)- These are changes in the current
featureC
branch relative to themaster
branch - These are changes which will be applied to
master
branch if we merge currentfeatureC
branch to it and only ifmaster
is a direct ancestor offeatureC
- These are changes in the current
- Everything is OK till the moment
master
branch has moved forward (since the point when we created the topic branch from it) - see the further‼️ Incorrect Way: Explanation‼️ item below
- We checkout to the branch
- Let's try to use
[user@pro13 schacon (featureC)]$ git checkout featureC
Already on 'featureC'
Your branch is up to date with 'origin/jessica/featureC'.
[user@pro13 schacon (featureC)]$ git diff master
diff --git a/featureC.txt b/featureC.txt
new file mode 100644
index 0000000..5b41842
--- /dev/null
+++ b/featureC.txt
@@ -0,0 +1,2 @@
+1-st commit
+2-nd commit
-
Let's see what happen if we do the same in various directions
-
1️⃣ Changes for
<left commit>..<right commit>
git diff <left commit> <right commit>
- changes between two arbitrary commits- These are changes in the
right commit
relative to theleft commit
- These are changes which will be applied to
left commit
if we mergeright commit
to it and only ifleft commit
is a direct ancestor ofright commit
- These are changes in the
git diff <left commit>..<right commit>
- this is synonymous to the previous form- Changes for
master..featureC
- These are changes in the
featureC
branch relative to themaster
branch - These are changes which will be applied to
master
branch if we merge currentfeatureC
branch to it and only ifmaster
is a direct ancestor offeatureC
- These are changes in the
[user@pro13 schacon (master)]$ git diff master..featureC # this is what we did above
diff --git a/featureC.txt b/featureC.txt
new file mode 100644
index 0000000..5b41842
--- /dev/null
+++ b/featureC.txt
@@ -0,0 +1,2 @@
+1-st commit
+2-nd commit
- 2️⃣ No changes for
<the same commit>..<the same commit>
- No changes for
featureC..featureC
- No changes for
[user@pro13 schacon (featureC)]$ git diff featureC #
[user@pro13 schacon (master)]$ git diff featureC..featureC # the same as above
- 3️⃣ No changes for
<the same commit>..<the same commit>
- No changes for
master..master
- No changes for
[user@pro13 schacon (featureC)]$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
[user@pro13 schacon (master)]$ git diff master # no changes for master..master
[user@pro13 schacon (master)]$ git diff master..master # the same as above
- 4️⃣ Changes for
<left commit>..<right commit>
- see item 1️⃣ above- Changes for
featureC..master
- These are changes in the
master
branch relative to thefeatureC
branch - These are changes which will be applied to
featureC
branch if we merge currentmaster
branch to it and only iffeatureC
is a direct ancestor ofmaster
- These are changes in the
- Changes for
[user@pro13 schacon (master)]$ git diff featureC..master # this is opposite of what we did initially above
diff --git a/featureC.txt b/featureC.txt
deleted file mode 100644
index 5b41842..0000000
--- a/featureC.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-1-st commit
-2-nd commit
[user@pro13 schacon (master)]$ git diff featureC # the same as above
diff --git a/featureC.txt b/featureC.txt
deleted file mode 100644
index 5b41842..0000000
--- a/featureC.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-1-st commit
-2-nd commit
[user@pro13 schacon (master)]$ git checkout featureC
Switched to branch 'featureC'
Your branch is up to date with 'origin/jessica/featureC'.
[user@pro13 schacon (featureC)]$ git diff featureC..master # it doesn't depend on the current working tree
diff --git a/featureC.txt b/featureC.txt
deleted file mode 100644
index 5b41842..0000000
--- a/featureC.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-1-st commit
-2-nd commit
‼️ Incorrect Way: Explanation‼️ - The command
[user@pro13 schacon (featureC)]$ git diff master
(run from checked outfeatureC
branch) is equal to thegit diff master..featureC
command - The command compares the snapshots of the last commit of the topic branch (
featureC
) and the snapshot of the last commit on themaster
branch - If the
master
branch has diverged (for example, if we’ve added a line in a file on themaster
branch), the diff will look like we’re adding all the new stuff in the topic branch (featureC
) and removing everything unique to themaster
branch - What we really want to see are the changes added to the topic branch (
featureC
) - the work we’ll introduce if we merge this branch withmaster
- We do that by having Git compare the last commit on the topic branch (
featureC
) with the first common ancestor it has with themaster
branch - We can use
git merge-base <commit> <commit>
command to figure out the common ancestor for the provided commits (<common ancestor for master and featureC>
) - We can use
<common ancestor for master and featureC>
running ingit diff
to determine the changes in the topic branch (featureC
) relative to the<common ancestor for master and featureC>
and these are changes which will be applied tomaster
branch if we merge currentfeatureC
branch to it - The command
[user@pro13 schacon (featureC)]$ git diff <common ancestor for master and featureC>
(run from checked outfeatureC
branch) is equal to thegit diff <common ancestor for master and featureC>..featureC
command - More concise command is
git diff $(git merge-base featureC master)
which shows the changes for<common ancestor for master and featureC>..featureC
- These are changes in the
featureC
branch relative to the<common ancestor for master and featureC>
- These are changes which will be applied to
master
branch if we merge currentfeatureC
branch to it whatevermaster
branch is a direct ancestor offeatureC
or not
- These are changes in the
- The command
[user@pro13 schacon (master)]$ git log --oneline --all
e7277bf (origin/jessica/featureC, featureC) featureC-2
9179f6b featureC-1
6c4e96c (HEAD -> master, origin/master, origin/HEAD) Initial commit
[user@pro13 schacon (master)]$ vi README.md
[user@pro13 schacon (master ✗)]$ git add .
[user@pro13 schacon (master ✗)]$ git commit -m "master-3"
[master 796e082] master-3
1 file changed, 2 insertions(+), 1 deletion(-)
[user@pro13 schacon (master)]$ git log --oneline --all --graph
* 796e082 (HEAD -> master) master-3
| * e7277bf (origin/jessica/featureC, featureC) featureC-2
| * 9179f6b featureC-1
|/
* 6c4e96c (origin/master, origin/HEAD) Initial commit
[user@pro13 schacon (master)]$ git diff master..featureC
diff --git a/README.md b/README.md
index 41a4412..bc15726 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1 @@
-# ch5
-3-rd commit
+# ch5
\ No newline at end of file
diff --git a/featureC.txt b/featureC.txt
new file mode 100644
index 0000000..5b41842
--- /dev/null
+++ b/featureC.txt
@@ -0,0 +1,2 @@
+1-st commit
+2-nd commit
[user@pro13 schacon (master)]$ git merge-base featureC master
6c4e96c097ad2645d5d8587f8338f94f1ae5ef87
[user@pro13 schacon (master)]$ git diff 6c4e96c097ad2645d5d8587f8338f94f1ae5ef87..featureC
diff --git a/featureC.txt b/featureC.txt
new file mode 100644
index 0000000..5b41842
--- /dev/null
+++ b/featureC.txt
@@ -0,0 +1,2 @@
+1-st commit
+2-nd commit
[user@pro13 schacon (master)]$ git checkout featureC
Switched to branch 'featureC'
Your branch is up to date with 'origin/jessica/featureC'.
[user@pro13 schacon (featureC)]$ git diff 6c4e96c097ad2645d5d8587f8338f94f1ae5ef87
diff --git a/featureC.txt b/featureC.txt
new file mode 100644
index 0000000..5b41842
--- /dev/null
+++ b/featureC.txt
@@ -0,0 +1,2 @@
+1-st commit
+2-nd commit
[user@pro13 schacon (featureC)]$ git diff $(git merge-base featureC master)
diff --git a/featureC.txt b/featureC.txt
new file mode 100644
index 0000000..5b41842
--- /dev/null
+++ b/featureC.txt
@@ -0,0 +1,2 @@
+1-st commit
+2-nd commit
- Git shorthand for doing the above thing in the context of the
git diff
is the 'triple-dot syntax'- The command
git diff A...B
is equivalent togit diff $(git merge-base A B) B
command - The command
git diff master...featureC
shows only the work the current topic branch (featureC
) has introduced since its common ancestor withmaster
- The command
[user@pro13 schacon (featureC)]$ git diff master...featureC
diff --git a/featureC.txt b/featureC.txt
new file mode 100644
index 0000000..5b41842
--- /dev/null
+++ b/featureC.txt
@@ -0,0 +1,2 @@
+1-st commit
+2-nd commit
- For
git diff <commit>...<commit>
omitting any one of<commits>
has the same effect as usingHEAD
instead
[user@pro13 schacon (featureC)]$ cat .git/HEAD
ref: refs/heads/featureC
[user@pro13 schacon (featureC)]$ git diff master...
diff --git a/featureC.txt b/featureC.txt
new file mode 100644
index 0000000..5b41842
--- /dev/null
+++ b/featureC.txt
@@ -0,0 +1,2 @@
+1-st commit
+2-nd commit
[user@pro13 schacon (featureC)]$ git co master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
[user@pro13 schacon (master)]$ git diff master...featureC
diff --git a/featureC.txt b/featureC.txt
new file mode 100644
index 0000000..5b41842
--- /dev/null
+++ b/featureC.txt
@@ -0,0 +1,2 @@
+1-st commit
+2-nd commit
[user@pro13 schacon (master)]$ cat .git/HEAD
ref: refs/heads/master
[user@pro13 schacon (master)]$ git diff ...featureC
diff --git a/featureC.txt b/featureC.txt
new file mode 100644
index 0000000..5b41842
--- /dev/null
+++ b/featureC.txt
@@ -0,0 +1,2 @@
+1-st commit
+2-nd commit
- See the totally different meaning for
git log
triple-dot range notation
[user@pro13 schacon (master)]$ git log --oneline --graph --all
* 796e082 (HEAD -> master) master-3
| * e7277bf (origin/jessica/featureC, featureC) featureC-2
| * 9179f6b featureC-1
|/
* 6c4e96c (origin/master, origin/HEAD) Initial commit
[user@pro13 schacon (master)]$ git log --oneline --graph master...featureC
* 796e082 (HEAD -> master) master-3
* e7277bf (origin/jessica/featureC, featureC) featureC-2
* 9179f6b featureC-1
[user@pro13 schacon (master)]$ git log --oneline --graph featureC...master
* 796e082 (HEAD -> master) master-3
* e7277bf (origin/jessica/featureC, featureC) featureC-2
* 9179f6b featureC-1
...
<rev>
Include commits that are reachable from <rev> (i.e. <rev> and its ancestors).
^<rev>
Exclude commits that are reachable from <rev> (i.e. <rev> and its ancestors).
<rev1>..<rev2>
Include commits that are reachable from <rev2> but exclude those that are reachable
from <rev1>. When either <rev1> or <rev2> is omitted, it defaults to HEAD.
<rev1>...<rev2>
Include commits that are reachable from either <rev1> or <rev2> but exclude those
that are reachable from both. When either <rev1> or <rev2> is omitted, it defaults
to HEAD.
...
...
git diff [<options>] <commit> [--] [<path>...]
This form is to view the changes you have in your working tree relative to the
named <commit>. You can use HEAD to compare it with the latest commit, or a
branch name to compare with the tip of a different branch.
git diff [<options>] <commit> <commit> [--] [<path>...]
This is to view the changes between two arbitrary <commit>.
git diff [<options>] <commit>..<commit> [--] [<path>...]
This is synonymous to the previous form. If <commit> on one side is omitted,
it will have the same effect as using HEAD instead.
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.
Just in case you are doing something exotic, it should be noted that all of
the <commit> in the above description, except in the last two forms that use
".." notations, can be any <tree>.
For a more complete list of ways to spell <commit>, see "SPECIFYING REVISIONS"
section in gitrevisions(7). However, "diff" is about comparing two endpoints,
not ranges, and the range notations ("<commit>..<commit>" and "<commit>...<commit>")
do not mean a range as defined in the "SPECIFYING RANGES" section in gitrevisions(7).
...