Friday, June 30, 2023

git merge: fast-forward merging

 

Currently, I am curious to find out what Git will do for us behind the scene if we run the 'git merge' commands. Below are the logs coming from my experiment. 


Reference: Git Book


Introduction


"Fast-forward merging" is the simplest scenario for the 'git merge'. But it is a rare case in reality.

The 'fast forward merging' required no new commit in the 'master' branch.


For instance, there are two branches 'master' and 'hotfix', and hotfix is one commit ahead from the master branch.

After fixing bugs C4 in the 'hotfix' branch, we want to merge our work to the master branch. And there is no new commit in the master branch, and it meets the 'fast forward merging' requirement. If it is fast-forward merging case, then the 'master' branch pointer will move to the last commit of the 'hotfix' branch.


Preparation


Create a brand new folder and run the 'git init' command.


Step 1:


Run the following commands to create c1, c2, and c3 commits.


    $ echo 'c1' > test.txt
$ git add .
$ git commit -m 'c1'
[master (root-commit) 09c1658] c1 1 file changed, 1 insertion(+) create mode 100644 test.txt

    $ echo 'c2' > test.txt
$ git add .
$ git commit -m 'c2'
[master f3333e2] c2 1 file changed, 1 insertion(+), 1 deletion(-)

    $ echo 'c3' > test.txt
$ git add .
$ git commit -m 'c3'
[master c9368a3] c3 1 file changed, 1 insertion(+), 1 deletion(-)


Check the git status.


    $ git status
On branch master nothing to commit, working tree clean


Check the .git tree structure.


    $ tree .git/
.git/ ├── COMMIT_EDITMSG ├── HEAD ├── branches ├── config ├── description ├── hooks │   ├── applypatch-msg.sample │   ├── commit-msg.sample │   ├── fsmonitor-watchman.sample │   ├── post-update.sample │   ├── pre-applypatch.sample │   ├── pre-commit.sample │   ├── pre-merge-commit.sample │   ├── pre-push.sample │   ├── pre-rebase.sample │   ├── pre-receive.sample │   ├── prepare-commit-msg.sample │   ├── push-to-checkout.sample │   └── update.sample ├── index ├── info │   └── exclude ├── logs │   ├── HEAD │   └── refs │   └── heads
│   └── master ├── objects     │   ├── 07 
    │   │   └── 71aea884dd394a7b12783d049f05b5599f41a4 (git blob object for c3)
    │   ├── 09 
    │   │   └── c165883d0a25f729d9a7c69fa02efd6c87c618 (git commit object for c1)
    │   ├── 16 
    │   │   └── f9ec009e5568c435f473ba3a1df732d49ce8c3  (git blob object for c2)
    │   ├── ae 
    │   │   └── 9304576a6ec3419b231b2b9c8e33a06f97f9fb (git blob object for c1)
    │   ├── b5 
    │   │   └── fab02de1c1f88003afeb7e98cf84a141bff039 (git tree object for c3)
    │   ├── c0 
    │   │   └── b072a3d368667939677b9315360631a100ecde (git tree object for c2)
    │   ├── c9 
    │   │   └── 368a318142494f31acd9c83a9763ed9f395a3b (git commit object for c3)
    │   ├── f1 
    │   │   └── 8c7b882bf09e79d96b692c31450cf59344fbf4 (git tree object for c1)
    │   ├── f3 
    │   │   └── 333e2df7930fa29ef8fb7ee177388f4a02b039 (git commit object for c2)
│   ├── info │   └── pack └── refs ├── heads
│   └── master └── tags 21 directories, 31 files


Check more info.


    $ cat .git/HEAD
ref: refs/heads/master

$ cat .git/refs/heads/master
c9368a318142494f31acd9c83a9763ed9f395a3b

$ git ls-files -s
100644 0771aea884dd394a7b12783d049f05b5599f41a4 0 test.txt

$ git log --oneline --decorate --graph --all
* c9368a3 (HEAD -> master) c3 * f3333e2 c2 * 09c1658 c1


Step 2:


Create and checkout a new branch 'hotfix'.


    $ git checkout -b hotfix
Switched to a new branch 'hotfix'


Check the git status.


    $ git status
On branch hotfix nothing to commit, working tree clean


Check the .git tree structure.


    $ tree .git/
.git/ ├── COMMIT_EDITMSG ├── HEAD ├── branches ├── config ├── description ├── hooks │   ├── applypatch-msg.sample │   ├── commit-msg.sample │   ├── fsmonitor-watchman.sample │   ├── post-update.sample │   ├── pre-applypatch.sample │   ├── pre-commit.sample │   ├── pre-merge-commit.sample │   ├── pre-push.sample │   ├── pre-rebase.sample │   ├── pre-receive.sample │   ├── prepare-commit-msg.sample │   ├── push-to-checkout.sample │   └── update.sample ├── index ├── info │   └── exclude ├── logs │   ├── HEAD │   └── refs │   └── heads
│   ├── hotfix
│   └── master ├── objects     │   ├── 07 
    │   │   └── 71aea884dd394a7b12783d049f05b5599f41a4 (git blob object for c3)
    │   ├── 09 
    │   │   └── c165883d0a25f729d9a7c69fa02efd6c87c618 (git commit object for c1)
    │   ├── 16 
    │   │   └── f9ec009e5568c435f473ba3a1df732d49ce8c3  (git blob object for c2)
    │   ├── ae 
    │   │   └── 9304576a6ec3419b231b2b9c8e33a06f97f9fb (git blob object for c1)
    │   ├── b5 
    │   │   └── fab02de1c1f88003afeb7e98cf84a141bff039 (git tree object for c3)
    │   ├── c0 
    │   │   └── b072a3d368667939677b9315360631a100ecde (git tree object for c2)
    │   ├── c9 
    │   │   └── 368a318142494f31acd9c83a9763ed9f395a3b (git commit object for c3)
    │   ├── f1 
    │   │   └── 8c7b882bf09e79d96b692c31450cf59344fbf4 (git tree object for c1)
    │   ├── f3 
    │   │   └── 333e2df7930fa29ef8fb7ee177388f4a02b039 (git commit object for c2)
│   ├── info │   └── pack └── refs ├── heads
│   ├── hotfix
│   └── master └── tags 21 directories, 33 files


Check more info.


    $ cat .git/HEAD
ref: refs/heads/hotfix

$ cat .git/refs/heads/master
c9368a318142494f31acd9c83a9763ed9f395a3b

$ cat .git/refs/heads/hotfix
c9368a318142494f31acd9c83a9763ed9f395a3b

$ git ls-files -s
100644 0771aea884dd394a7b12783d049f05b5599f41a4 0 test.txt

$ git log --oneline --decorate --graph --all
* c9368a3 (HEAD -> hotfix, master) c3
* f3333e2 c2 * 09c1658 c1

Both the hotfix branch and the master branch point to the c3 commit.


Step 3:


Create a new commit 'c4' on the hotfix branch.


    $ echo 'c4' > test.txt
    $ git add .
    $ git commit -m 'c4'
[hotfix 85ad7e6] c4
 1 file changed, 1 insertion(+), 1 deletion(-)


Check the git status.


    $ git status
On branch hotfix nothing to commit, working tree clean


Check the .git tree structure.


    $ tree .git/
.git/ ├── COMMIT_EDITMSG ├── HEAD ├── branches ├── config ├── description ├── hooks │   ├── applypatch-msg.sample │   ├── commit-msg.sample │   ├── fsmonitor-watchman.sample │   ├── post-update.sample │   ├── pre-applypatch.sample │   ├── pre-commit.sample │   ├── pre-merge-commit.sample │   ├── pre-push.sample │   ├── pre-rebase.sample │   ├── pre-receive.sample │   ├── prepare-commit-msg.sample │   ├── push-to-checkout.sample │   └── update.sample ├── index ├── info │   └── exclude ├── logs │   ├── HEAD │   └── refs │   └── heads
│   ├── hotfix
│   └── master ├── objects     │   ├── 07 
    │   │   └── 71aea884dd394a7b12783d049f05b5599f41a4 (git blob object for c3)
    │   ├── 09 
    │   │   └── c165883d0a25f729d9a7c69fa02efd6c87c618 (git commit object for c1)
    │   ├── 16 
    │   │   └── f9ec009e5568c435f473ba3a1df732d49ce8c3  (git blob object for c2)
    │   ├── 3d
    │   │   └── 3095743da8025788f376069d9c07b9d867d5c1 (git tree object for c4)
    │   ├── 85
    │   │   └── ad7e6b045bfc28bf4546a86f1e9b0b669fc034 (git commit object for c4)
    │   ├── a1
    │   │   └── 03f673dd1b7c5727aa0ae0100419adc50e1b76 (git blob object for c4)
    │   ├── ae 
    │   │   └── 9304576a6ec3419b231b2b9c8e33a06f97f9fb (git blob object for c1)
    │   ├── b5 
    │   │   └── fab02de1c1f88003afeb7e98cf84a141bff039 (git tree object for c3)
    │   ├── c0 
    │   │   └── b072a3d368667939677b9315360631a100ecde (git tree object for c2)
    │   ├── c9 
    │   │   └── 368a318142494f31acd9c83a9763ed9f395a3b (git commit object for c3)
    │   ├── f1 
    │   │   └── 8c7b882bf09e79d96b692c31450cf59344fbf4 (git tree object for c1)
    │   ├── f3 
    │   │   └── 333e2df7930fa29ef8fb7ee177388f4a02b039 (git commit object for c2)
│   ├── info │   └── pack └── refs ├── heads
│   ├── hotfix
│   └── master └── tags 24 directories, 36 files


Check more info.


    $ cat .git/HEAD
ref: refs/heads/hotfix

$ cat .git/refs/heads/master
c9368a318142494f31acd9c83a9763ed9f395a3b

$ cat .git/refs/heads/hotfix
85ad7e6b045bfc28bf4546a86f1e9b0b669fc034

$ git ls-files -s
100644 a103f673dd1b7c5727aa0ae0100419adc50e1b76 0 test.txt

$ git log --oneline --decorate --graph --all
* 85ad7e6 (HEAD -> hotfix) c4 * c9368a3 (master) c3 
* f3333e2 c2 * 09c1658 c1

Now the hotfix branch has one more commit ahead the master branch.


Step 4:


Switch to the master branch. 

Run the 'git merge' command to merge the work from the hotfix branch.


    $ git checkout master
Switched to branch 'master'

    $ git merge hotfix
Updating c9368a3..85ad7e6
Fast-forward
 test.txt | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

c9368a3 is the last commit from the master branch.

85ad7e6 is the last commit from the hotfix branch, and the master branch will point to it after merging.


Check the git status.


    $ git status
On branch master nothing to commit, working tree clean


Check the .git tree structure.


    $ tree .git/
.git/ ├── COMMIT_EDITMSG ├── HEAD 
├── ORIG_HEAD
├── branches ├── config ├── description ├── hooks │   ├── applypatch-msg.sample │   ├── commit-msg.sample │   ├── fsmonitor-watchman.sample │   ├── post-update.sample │   ├── pre-applypatch.sample │   ├── pre-commit.sample │   ├── pre-merge-commit.sample │   ├── pre-push.sample │   ├── pre-rebase.sample │   ├── pre-receive.sample │   ├── prepare-commit-msg.sample │   ├── push-to-checkout.sample │   └── update.sample ├── index ├── info │   └── exclude ├── logs │   ├── HEAD │   └── refs │   └── heads
│   ├── hotfix
│   └── master ├── objects     │   ├── 07 
    │   │   └── 71aea884dd394a7b12783d049f05b5599f41a4 (git blob object for c3)
    │   ├── 09 
    │   │   └── c165883d0a25f729d9a7c69fa02efd6c87c618 (git commit object for c1)
    │   ├── 16 
    │   │   └── f9ec009e5568c435f473ba3a1df732d49ce8c3  (git blob object for c2)
    │   ├── 3d
    │   │   └── 3095743da8025788f376069d9c07b9d867d5c1 (git tree object for c4)
    │   ├── 85
    │   │   └── ad7e6b045bfc28bf4546a86f1e9b0b669fc034 (git commit object for c4)
    │   ├── a1
    │   │   └── 03f673dd1b7c5727aa0ae0100419adc50e1b76 (git blob object for c4)
    │   ├── ae 
    │   │   └── 9304576a6ec3419b231b2b9c8e33a06f97f9fb (git blob object for c1)
    │   ├── b5 
    │   │   └── fab02de1c1f88003afeb7e98cf84a141bff039 (git tree object for c3)
    │   ├── c0 
    │   │   └── b072a3d368667939677b9315360631a100ecde (git tree object for c2)
    │   ├── c9 
    │   │   └── 368a318142494f31acd9c83a9763ed9f395a3b (git commit object for c3)
    │   ├── f1 
    │   │   └── 8c7b882bf09e79d96b692c31450cf59344fbf4 (git tree object for c1)
    │   ├── f3 
    │   │   └── 333e2df7930fa29ef8fb7ee177388f4a02b039 (git commit object for c2)
│   ├── info │   └── pack └── refs ├── heads
│   ├── hotfix
│   └── master └── tags 24 directories, 37 files


Check more info.


    $ cat .git/HEAD
ref: refs/heads/master

    $ cat .git/ORIG_HEAD
c9368a318142494f31acd9c83a9763ed9f395a3b

$ cat .git/refs/heads/master
85ad7e6b045bfc28bf4546a86f1e9b0b669fc034

$ cat .git/refs/heads/hotfix
85ad7e6b045bfc28bf4546a86f1e9b0b669fc034

$ git ls-files -s
100644 a103f673dd1b7c5727aa0ae0100419adc50e1b76 0 test.txt

$ git log --oneline --decorate --graph --all
* 85ad7e6 (HEAD -> master, hotfix) c4 * c9368a3 c3 * f3333e2 c2 * 09c1658 c1


ORIG_HEAD was created after running the 'git merge' command.

It is used to revert the merge commit singe git thinks that the 'merge command' is dangerous and easy to make a mistake.


No comments:

Post a Comment