We should discuss the difference between fast-forward and the 3-way merge before introducing the 'git rebase'
*Fast-forward
When the merging branch (bugFix) has all commits from the current branch (master), Git will not create a new merging commit. Instead, it will move the 'master' branch pointer to the latest commit of the 'bugfix' branch. It is a line (linear path) relationship.
*3 way merge
When the current branch (master) contains commits that the merging branch (bugfix) doesn't have, Git will create a new merging commit that merges two branches without modifying the existing branches. It is a tree (with a cycle) relationship.
Therefore, if we don't want to make it to create a new commit that is used for merging two branches, then we need to try to make the git structure to be Fast-Forward. Then the 'git rebase' command can help!
Rebase
Copies commit on top of another branch without creating a commit, which keeps a linear history. Git will delete the old changes and rewrite them (with new sha1) on the top of the latest target (master) branch.
// Each branch has a new commit.
(master)
C1 -> C2
-> C3
(bugfix)
// After rebase, it turns into linear history
(master)
C1 -> C2
-> C2 -> C4 (rewritten commit from C3)
(bugfix)
NOTE:
1. Conflicts might be happened as usual, and we need to resolve them manually.
2. Rebase is not suitable if multiple people use the same branch.
3. The master branch is better not to do rebase
Below are the logs from my experiment (Rebasing without conflicts)
Step 1:
Check the status of the master branch
$ git log
commit cd1374abfde32ce13bc55f1abbb77571f230dedc (HEAD -> master)
Author: Frank <frank@demo.com>
Date: Timestamp
second commit by master
commit 54a804e5f7e75c74f5380cc097336957ca756f9f
Author: Frank <frank@demo.com>
Date: Timestamp
first commit
Step 2:
Switch to the bugFix branch and check the status.
$ git checkout bugFix
Switched to branch 'bugFix'
$ git log
commit 38b42c91af547bd80692fae406ab6b325300b173 (HEAD -> bugFix)
Author: Frank <frank@demo.com>
Date: Timestamp
first commit in bugFix
commit 54a804e5f7e75c74f5380cc097336957ca756f9f
Author: Frank <frank@demo.com>
Date: Timestamp
first commit
Step 3:
Check the git structure.
$ tree .git/
.git/
├── COMMIT_EDITMSG
├── HEAD
├── config
├── description
├── hooks
├── index
├── info
│ └── exclude
├── logs
│ ├── HEAD
│ └── refs
│ └── heads
│ ├── bugfix
│ └── master
├── objects
│ ├── 18
│ │ └── 0cf8328022becee9aaa2577a8f84ea2b9f3827
│ ├── 34
│ │ └── 84292db2aec3ad938ac17d3daf55dac8b03075
│ ├── 38
│ │ └── b42c91af547bd80692fae406ab6b325300b173
│ ├── 54
│ │ └── a804e5f7e75c74f5380cc097336957ca756f9f
│ ├── 81
│ │ └── fa9d1c5348f86326ce5e7a86d11b54c8140d8d
│ ├── a5
│ │ └── bce3fd2565d8f458555a0c6f42d0504a848bd5
│ ├── b4
│ │ └── 1fb42483f661a1de6202b2a872de08638acb9c
│ ├── c0
│ │ └── da834e42dcbf7b2b1c4a97925bef105d3863a3
│ ├── cd
│ │ └── 1374abfde32ce13bc55f1abbb77571f230dedc
│ ├── info
│ └── pack
└── refs
├── heads
│ ├── bugfix
│ └── master
└── tags
20 directories, 20 files
Step 4:
Run the 'git rebase' command from master in the current bugFix branch.
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: first commit in bugfix
According to the message above, the commit 'first commit in bugfix' will be rewritten.
Step 5:
Check the status of the bugFix branch.
$ git log
commit 0238eb360ced00720a6efffbbc6c8f372eaf3c0d (HEAD -> bugFix)
Author: Frank <frank@demo.com>
Date: Timestamp
first commit in bugFix
commit cd1374abfde32ce13bc55f1abbb77571f230dedc (master)
Author: Frank <frank@demo.com>
Date: Timestamp
second commit by master
commit 54a804e5f7e75c74f5380cc097336957ca756f9f
Author: Frank <frank@demo.com>
Date: Timestamp
first commit
1. Now, the new commit cd1374 from the master branch is copied to the bugfix branch.
2. You will notice that the sha1 of 'first commit in bugfix' is changed from '38b42c' to '0238eb'.
Step 6:
Compare the git structure.
$ tree .git/
.git/
├── COMMIT_EDITMSG
├── HEAD
├── ORIG_HEAD (NEW FILE)
├── config
├── description
├── hooks
├── index
├── info
│ └── exclude
├── logs
│ ├── HEAD
│ └── refs
│ └── heads
│ ├── bugfix
│ └── master
├── objects
│ ├── 02 (NEW FOLDER)
│ │ └── 38eb360ced00720a6efffbbc6c8f372eaf3c0d (NEW FILE, rewritten commit)
│ ├── 18
│ │ └── 0cf8328022becee9aaa2577a8f84ea2b9f3827
│ ├── 34
│ │ └── 84292db2aec3ad938ac17d3daf55dac8b03075
│ ├── 38
│ │ └── b42c91af547bd80692fae406ab6b325300b173
│ ├── 54
│ │ └── a804e5f7e75c74f5380cc097336957ca756f9f
│ ├── 5a (NEW FOLDER)
│ │ └── 3d043807c15183f3936b4e179acee9c0e2f26a (NEW FILE)
│ ├── 81
│ │ └── fa9d1c5348f86326ce5e7a86d11b54c8140d8d
│ ├── a5
│ │ └── bce3fd2565d8f458555a0c6f42d0504a848bd5
│ ├── b4
│ │ └── 1fb42483f661a1de6202b2a872de08638acb9c
│ ├── c0
│ │ └── da834e42dcbf7b2b1c4a97925bef105d3863a3
│ ├── cd
│ │ └── 1374abfde32ce13bc55f1abbb77571f230dedc
│ ├── info
│ └── pack
└── refs
├── heads
│ ├── bugfix
│ └── master
└── tags
22 directories, 23 files
Check the rewritten commit.
$ git cat-file -p 0238eb
tree 5a3d043807c15183f3936b4e179acee9c0e2f26a
parent cd1374abfde32ce13bc55f1abbb77571f230dedc
author Frank <frank@demo.com>
committer Frank <frank@demo.com>
first commit in bugfix
$ git cat-file -p 5a3d04
100644 blob b41fb42483f661a1de6202b2a872de08638acb9c test1.txt
100644 blob 180cf8328022becee9aaa2577a8f84ea2b9f3827 test2.txt
Step 7:
Switch to the master branch and do the 'git merge' command.
$ git checkout master
Switched to branch 'master'
$ git merge bugFix
Updating cd1374a..0238eb3
Fast-forward
test2.txt | 1 +
1 file changed, 1 insertion(+)
create mode 100644 test2.txt
It is fast-forward, not 3 way merge