git: merge vs. rebase
After my lunch & learn talk, I realized I did not go over the difference between rebase and merge, two techniques to get work into a branch from another.

Suppose you have a repo with two branches:
- master
- testing
The repository is available here
The main difference between testing & master branches:
ec0d: common parent to both creates the file: important_file.txtc02b: master adds a line to the important_file.txtc2a5: testing adds a new file: testing_file.txt
Details of common parent to master and testing: ec0d
vagrant@ubuntu-xenial:/vagrant$ git show ec0d
commit ec0dde385a2d36db33451ec977d796d0c03cc6b4 (HEAD)
Author: Andrew Leung <andrew@ualberta.net>
Date: Thu Apr 18 07:54:57 2019 -0400
FIX: Add important file contents
diff --git a/important_file.txt b/important_file.txt
index e69de29..0b438af 100644
--- a/important_file.txt
+++ b/important_file.txt
@@ -0,0 +1,3 @@
+IMPORTANT FILE
+
+DO NOT ERASEDetails of the commit added to master: c02b
vagrant@ubuntu-xenial:/vagrant$ git show c02b
commit c02bd5fa53e0513d91b0e2545573bb8f18acb9a5 (master)
Author: Andrew Leung <andrew@ualberta.net>
Date: Thu Apr 18 07:59:12 2019 -0400
FIX: Enhance important file
diff --git a/important_file.txt b/important_file.txt
index 0b438af..652404b 100644
--- a/important_file.txt
+++ b/important_file.txt
@@ -1,3 +1,5 @@
IMPORTANT FILE
DO NOT ERASE
+
+REALLY DO NOT ERASEDetails of the one commit added to testing: c2a5
vagrant@ubuntu-xenial:/vagrant$ git show c2a5
commit c2a5c4a7b45305c52dc6c729d813974689391cc9 (testing)
Author: Andrew Leung <andrew@ualberta.net>
Date: Thu Apr 18 07:58:12 2019 -0400
FEATURE: Add testing file
diff --git a/testing_file.txt b/testing_file.txt
new file mode 100644
index 0000000..884c301
--- /dev/null
+++ b/testing_file.txt
@@ -0,0 +1,3 @@
+TESTING FILE
+
+ONLY FOR TESTING PURPOSESSummary of repository branches:
ec0d: common parent, creates important filec02b: master branch - extends important filec2a5: testing branch - adds testing file
Let’s get changes from testing (c2a5) onto master (c02b) using the
two common ways in git: merge and rebase.
Merge
Let’s get changes from the testing branch, c2a5, onto the master
branch, c02b by merging, and using a different branch aptly named:
merge_testing_to_master:
vagrant@ubuntu-xenial:/vagrant$ git checkout master
Switched to branch 'master'
vagrant@ubuntu-xenial:/vagrant$ git checkout -b merge_testing_to_master
Switched to a new branch 'merge_testing_to_master'
vagrant@ubuntu-xenial:/vagrant$ git merge testing
# make user entry for merge
Merge made by the 'recursive' strategy.
testing_file.txt | 3 +++
1 file changed, 3 insertions(+)
create mode 100644 testing_file.txtLet’s look at the result via $ git log --graph:
vagrant@ubuntu-xenial:/vagrant$ git log --graph --oneline
* ea824a6 (HEAD -> merge_testing_to_master) Merge branch 'testing' into merge_testing_to_master
|\
| * c2a5c4a (testing) FEATURE: Add testing file
* | c02bd5f (master) FIX: Enhance important file
|/
* ec0dde3 FIX: Add important file contents
* ef43cae FEATURE: include important file
* 597d771 initial commitNotice that the new merge commit, ea82, points to the testing
branch, c2a5, and master branch, c02b.
Rebase
Now, let’s do the same thing: get changes onto the testing branch,
c2a5, onto the master branch, c02b, using the rebase technique on
a new branch, aptly named: rebase_testing_to_master:
vagrant@ubuntu-xenial:/vagrant$ git checkout master
Switched to branch 'master'
vagrant@ubuntu-xenial:/vagrant$ git checkout -b rebase_testing_to_master
Switched to a new branch 'rebase_testing_to_master'
vagrant@ubuntu-xenial:/vagrant$ git rebase testing
First, rewinding head to replay your work on top of it...
Applying: FIX: Enhance important file
vagrant@ubuntu-xenial:/vagrant$Let’s take a look at the result using $ git log --graph:
vagrant@ubuntu-xenial:/vagrant$ git log --graph --oneline
* e4607f4 (HEAD -> rebase_testing_to_master) FIX: Enhance important file
* c2a5c4a (testing) FEATURE: Add testing file
* ec0dde3 FIX: Add important file contents
* ef43cae FEATURE: include important file
* 597d771 initial commitNotice that there is no commit between the master and testing branches
as in the merge technique. The master commit, c02b, does not appear
in this branch’s history, BUT there is a new commit, e460, which has
the same commit message as the, c02b master commit:
FIX: Enhance important file
The details of the e460 change is:
vagrant@ubuntu-xenial:/vagrant$ git show e460
commit e4607f487df0159b33001067e999aa1479b944da (rebase_testing_to_master)
Author: Andrew Leung <andrew@ualberta.net>
Date: Thu Apr 18 07:59:12 2019 -0400
FIX: Enhance important file
diff --git a/important_file.txt b/important_file.txt
index 0b438af..652404b 100644
--- a/important_file.txt
+++ b/important_file.txt
@@ -1,3 +1,5 @@
IMPORTANT FILE
DO NOT ERASE
+
+REALLY DO NOT ERASENotice that this new commit has exactly the same contents as the
original master commit, c02b:
vagrant@ubuntu-xenial:/vagrant$ git show c02b
commit c02bd5fa53e0513d91b0e2545573bb8f18acb9a5 (master)
Author: Andrew Leung <andrew@ualberta.net>
Date: Thu Apr 18 07:59:12 2019 -0400
FIX: Enhance important file
diff --git a/important_file.txt b/important_file.txt
index 0b438af..652404b 100644
--- a/important_file.txt
+++ b/important_file.txt
@@ -1,3 +1,5 @@
IMPORTANT FILE
DO NOT ERASE
+
+REALLY DO NOT ERASEEven down to the file change: index 0b438af..652404b 100644
Differences
The $ git diff of the branches produces no differences:
vagrant@ubuntu-xenial:/vagrant$ git diff merge_testing_to_master rebase_testing_to_master
vagrant@ubuntu-xenial:/vagrant$History Difference
The only place where there is a difference is the history of the
branches, the merge technique introduced a new merge commit, ea82,
while the rebase technique changed the master commit from: c02b to
e460.
The rebase took the work of the testing branch, c2a5, and put it
underneath the current master branch, c02b, and making a new commit
for it, e460.
Big Picture
Taking a look at all the branches using $ git log --graph --all
--oneline shows:
vagrant@ubuntu-xenial:/vagrant$ git log --graph --all --oneline
* e4607f4 (rebase_testing_to_master) FIX: Enhance important file
| * ea824a6 (merge_testing_to_master) Merge branch 'testing' into merge_testing_to_master
| |\
| |/
|/|
* | c2a5c4a (testing) FEATURE: Add testing file
| * c02bd5f (master) FIX: Enhance important file
|/
* ec0dde3 (HEAD) FIX: Add important file contents
* ef43cae FEATURE: include important file
* 597d771 initial commitBoth branches share a common parent in current HEAD, ec0d, but where
they end up afterwards is slightly different, both produce their own
path forward:
- rebase made everything linear by recommiting the master work on top of the testing work
- merge created a new commit, referencing both master and testing
Options, options
Which one should you use? I prefer to rebase everything so the work of the branch HEAD points to is ahead of everything else. I am a bit annoyed with merges since it creates another commit.
Conclusion
To get work from another branch onto the current branch, there are
git rebase and git merge.
Rebasing creates a new commit of the current work and “slides” all the other branch’s work underneath. Keeping history in a linear fashion.
Merging creates a new commit that points to both the current branch and the other branch’s work.
Which one to use is a personal preference, but I tend to prefer rebasing over merging, only to keep history clean.