2022-03-28-Git detached head 分析
博客迁移:不恰饭的小站
https://blog.buqia.fun/2022/03/28/2022-03-28-Git%20detach%20head%20%E5%88%86%E6%9E%90/
1. Git detached head 的含义#
detached head 是一种 HEAD 指针指向了某一个具体的 commit id,而不是分支名称(master、…)的情况。
2. Git detached head 的产生、操作与消亡#
产生:
git checkout 到一个 commit ID操作:
git checkout -b foo (1)
creates a new branch foo, which refers to commit f, and then updates HEAD to refer to branch foo. In other words, we’ll no longer be in detached HEAD state after this command.git branch foo (2)
similarly creates a new branch foo, which refers to commit f, but leaves HEAD detached.git tag foo (3)
creates a new tag foo, which refers to commit f, leaving HEAD detached.
消亡:
detached head 会由 Git 垃圾回收机制回收
3. Git detached head 的 man 手册#
HEAD normally refers to a named branch (e.g. master). Meanwhile, each branch refers to a specific commit. Let’s look at a repo with three commits, one of them tagged, and with branch master checked out:
1 | HEAD (refers to branch 'master') |
When a commit is created in this state, the branch is updated to refer to the new commit. Specifically, git commit creates a new commit d, whose parent is commit c, and then updates branch master to refer to new commit d. HEAD still refers to branch master and so indirectly now refers to commit d:
1 | $ edit; git add; git commit |
It is sometimes useful to be able to checkout a commit that is not at the tip of any named branch, or even to create a new commit that is not referenced by a named branch. Let’s look at what happens when we checkout commit b (here we show two ways this may be done):
1 | $ git checkout v2.0 # or |
Notice that regardless of which checkout command we use, HEAD now refers directly to commit b. This is known as being in detached HEAD state. It means simply that HEAD refers to a specific commit, as opposed to referring to a named branch. Let’s see what happens when we create a commit:
1 | $ edit; git add; git commit |
There is now a new commit e, but it is referenced only by HEAD. We can of course add yet another commit in this state:
1 | $ edit; git add; git commit |
In fact, we can perform all the normal Git operations. But, let’s look at what happens when we then checkout master:
1 | $ git checkout master |
It is important to realize that at this point nothing refers to commit f. Eventually commit f (and by extension commit e) will be deleted by the routine Git garbage collection process, unless we create a reference before that happens. If we have not yet moved away from commit f, any of these will create a reference to it:
1 | $ git checkout -b foo (1) |
creates a new branch foo, which refers to commit f, and then updates HEAD to refer to branch foo. In other words, we’ll no longer be in detached HEAD state after this command.
similarly creates a new branch foo, which refers to commit f, but leaves HEAD detached.
creates a new tag foo, which refers to commit f, leaving HEAD detached.
If we have moved away from commit f, then we must first recover its object name (typically by using git reflog), and then we can create a reference to it. For example, to see the last two commits to which HEAD referred, we can use either of these commands:
1 | $ git reflog -2 HEAD # or |
4. 应用场景分析#
- 临时看一下某个提交的内容, 不做修改
- 利用 游离状态的版本号创建一个新的分支
5. 实践#
- 创建初始
1 | git init |
- 创建三次提交
1 | touch a |
- git log
1 | commit 76617d0b28d7d02516f195851fddcb7654c40a19 (HEAD -> master) |
- 产生 detached HEAD
git checout e0fb0f1c9ab9bdfcd3e4f60b2321d152926b3b40
1 | Note: checking out 'e0fb0f1c9ab9bdfcd3e4f60b2321d152926b3b40'. |
- 以此创建新分支,并消除 detached Head
1 | git checkout -b new |
- 切换到 master
1 | git checkout master |
- 在主线
git log
1 | commit 671f275294d84d322fffed7f52fd412223a69f07 (HEAD -> master) |
git reflog
1 | 671f275 (HEAD -> master) HEAD@{0}: commit: e |
2022-03-28-Git detached head 分析
https://blog.buqia.fun/2022/03/28/2022-03-28-Git detach head 分析/