Sunday, June 25, 2023

git: detached HEAD

  

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


HEAD is a pointer that can point to Git branches or commits. If it points to a branch, it will know which commit it refers to since branches are pointers to point to a commit.

Also, HEAD pointer can point to a commit directly, and it is called 'detached HEAD' in this case.


Preparation


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

Then run the following commands.


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

    $ echo 'test2' > test2.txt
$ git add .
$ git commit -m 'second commit'
[master a75a437] second commit 1 file changed, 1 insertion(+) create mode 100644 test2.txt

    $ echo 'test3' > test3.txt
$ git add .
$ git commit -m 'third commit'
[master 29f19e1] third commit 1 file changed, 1 insertion(+) create mode 100644 test3.txt


Step 1:


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 │   ├── 18 │   │   └── 0cf8328022becee9aaa2577a8f84ea2b9f3827 │   ├── 29 │   │   └── f19e1550aa1491fabc30bb99fdb8fc8180cf55 │   ├── 2b │   │   └── 297e643c551e76cfa1f93810c50811382f9117 │   ├── 59 │   │   └── 50f5c8ec9efcb96612f89264fd72994badb828 │   ├── 78 │   │   └── d3e4b3599492d1f9214d8baf3fd954a17045ff │   ├── 9d │   │   └── aeafb9864cf43055ae93beb0afd6c7d144bfa4 │   ├── a7 │   │   └── 5a437bbcf6e57ed7d83a6ad31ccda9e78685ea │   ├── de │   │   └── ecd29ff1a94c4a4d453edeeff6a1e7df223e93 │   ├── df │   │   └── 6b0d2bcc76e6ec0fca20c227104a4f28bac41b │   ├── info │   └── pack └── refs ├── heads │   └── master └── tags 21 directories, 31 files


Check the HEAD pointer and branch pointers info.


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

$ cat .git/refs/heads/master
29f19e1550aa1491fabc30bb99fdb8fc8180cf55

$ git log --oneline --decorate --graph --all
* 29f19e1 (HEAD -> master) third commit * a75a437 second commit * deecd29 first commit


The HEAD pointer points to the master branch.

The master branch points to '29f19e' commit.



Step 2:


Checkout the first commit 'deecd29'.


    $ git checkout deecd29
Note: switching to 'deecd29'. You are in 'detached HEAD' state. You can look around, make experimental changes and commit them, and you can discard any commits you make in this state without impacting any branches by switching back to a branch. If you want to create a new branch to retain commits you create, you may do so (now or later) by using -c with the switch command. Example: git switch -c <new-branch-name> Or undo this operation with: git switch - Turn off this advice by setting config variable advice.detachedHead to false HEAD is now at deecd29 first commit


Check the CMD:


    frank: ~/Projects/exp ((HEAD detached at deecd29))


The HEAD points to deecd29 commit directly.


    $ cat .git/HEAD
    deecd29ff1a94c4a4d453edeeff6a1e7df223e93


Check the log.


    $ git log --oneline --decorate --graph --all
* 29f19e1 (master) third commit * a75a437 second commit * deecd29 (HEAD) first commit



Step 3:


In practice, we should create a branch before making any changes.

So let's try to create a branch 'hotfix'

Create a branch pointing to this commit because in practice, we will create a branch before making changes.


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

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

    $ cat .git/refs/heads/hotfix
    deecd29ff1a94c4a4d453edeeff6a1e7df223e93

    $ git log --oneline --decorate --graph --all
* 29f19e1 (master) third commit * a75a437 second commit * deecd29 (HEAD -> hotfix) first commit



Step 4:


Create a new commit. 


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


Check the log.


    $ git log --oneline --decorate --graph --all
* a48ebd5 (HEAD -> hotfix) fix sth | * 29f19e1 (master) third commit | * a75a437 second commit |/ * deecd29 first commit



Then we can merge those hotfix change to the master branch easily.

 

No comments:

Post a Comment