結論
detached HEADとはHEADのリファレンスがブランチではない状態とのことを言います
用語
本記事で出てくるGitの用語は以下にまとめておきます。
用語 | 説明 |
---|---|
HEAD | 現在の作業位置を指すタグ |
カレントブランチ | 現在チェックアウト中のブランチ |
リファレンス | 特定のコミットを指すポインタ |
SHA-1 | コミットを一意に識別するハッシュ値 |
説明
HEADは何も指定しなければ通常、リファレンスとしてカレントブランチを指定しています。
もし、作業しているコミットを移動したい場合はブランチ名もしくはSHA-1を指定してHEADの移動が可能です。
この時ブランチ名を指定せず、SHA-1をした場合はdetached HEAD
という状態になります。
detachedは切り離されたという意味の英語で、detached HEAD
とはHEADがブランチから切り離されている状態となります
detached HEADの状態にする
以下がHEADの位置を変更する前の状態です
$ git log -n 3 --oneline
a2f9e77 (HEAD -> feature) add Repository package
be9b967 add Service package
af931c7 (origin/main, main) サンプルコントローラ追加
このHEADの位置をSHA-1がbe9b967
のコミット(イメージではコミットB)に移動します。
$ git checkout be9b967
Note: switching to 'be9b967'.
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 be9b967 add Service package
これで移動が完了しました。
You are in 'detached HEAD' state.
ここを確認すると、HEADがdetachedの状態になっていることが分かります。
detached HEAD状態で出来ること出来ないこと
HEADを移動することで、特定のコミット時点に戻ることができます。
ただし、コミット時の挙動など、通常の状態とは違う動きになるものもあるので確認していきましょう。
コミット
試しに適当なファイルをdetached HEAD状態でコミットします。
$ git commit -m "add txt file"
[detached HEAD 4fed63f] add txt file
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 src/main/java/com/example/git/GitSample/controller/2.txt
イメージ図の右側にあるコミットDが新規コミットとなります。
HEADのリファレンスもコミットDに移動しています。
重要なポイントとしては、どのブランチもコミットDを参照していない(辿れない)ということです。
HEADのみが参照できる状態なので、HEADを移動させるとコミットDは宙に浮いてどこからも参照できなくなります。
これについては、HEADを最初移動した時に、出力されていた情報に記載されているので抜粋します。
you can discard any commits you make in this
state without impacting any branches by switching back to a branch.
元のブランチに戻ることで作成したコミットを取り消せることが記載されています。
ただし、このコミットを保持する方法もいくつかあるので紹介していきます。
ブランチを新規作成してコミットを保持する
コミットを保持する方法の一つは、HEADを最初移動した時に、出力されていた情報に記載されているので抜粋します。
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>
作成したコミットを保持したい場合は、git switch -c <new-branch-name>
を利用して新しいブランチを作成するように記載されています。
実際にやってみます。
$ git switch -c backup
Switched to a new branch 'backup'
イメージ図
backupブランチを作成してコミットDを参照するようになりました。
これでHEADを移動しても、backupブランチからコミットDに戻れます。
reflogで復元する
reflogは HEADの移動履歴を確認できる機能です。
これでHEADを移動させた後でも、宙に浮いたコミットを見つけることができます。
まずは、宙に浮いたコミットを作成するため以下の手順を実施します
1.detached HEAD状態にする
2.コミットを作成する
3.HEADを別のブランチに移動する
$ git checkout feature
Warning: you are leaving 1 commit behind, not connected to
any of your branches:
257b100 add txt file
If you want to keep it by creating a new branch, this may be a good time
to do so with:
git branch <new-branch-name> 257b100
Switched to branch 'feature'
「1.」「2.」は事前に実行しています。
「3.」実行結果の警告として1つのコミットがどのブランチからも参照されていないことが記載されています
イメージ図で言うところのコミットDがどのブランチからも参照されていません。
ただし、コミットDのSHA-1が分かれば復元が可能です。
reflogを利用すれば、HEADの移動履歴からSHA-1を確認できます。
$ git reflog -n 3
a2f9e77 (HEAD -> feature) HEAD@{0}: checkout: moving from 257b100007270c6e8893043c96fd2e8afde894a8 to feature
257b100 HEAD@{1}: commit: add txt file
be9b967 HEAD@{2}: checkout: moving from feature to be9b967
コミットDのSHA-1が257b100
であることが分かりました。
後は257b100
を対象にブランチを作成することで再度参照が可能になります。
$ git switch -c rescue 257b100
Switched to a new branch 'rescue'
まとめ
今回はdetached HEADの概要と特徴についてまとめました。
質問や指摘等あれば是非コメントよろしくお願いします。