「HEADが外れた」と言われても困る
Gitを触っていると、ある日突然こんなメッセージが出てきます。
You are in 'detached HEAD' state.
英語で長々と説明が続くので、正直最初は「何かやらかしたのでは」と焦ります。でもこれはエラーではなく、Gitが「今あなたはちょっと特殊な場所に立っていますよ」と教えてくれている状態表示です。
まず HEAD が何なのかを整理する
Gitには「今どこを見ているか」を示す目印があって、それが HEAD です。ふだんは main や feature/login といったブランチ名を指しています。
ブランチ名というのは、実は「最新のコミットを指す動く付箋」みたいなものです。コミットするたびに、付箋が自動的に新しいコミットへずれていきます。そしてHEADはその付箋を指しているので、あなたがコミットすれば、付箋もHEADも一緒に前へ進みます。
detached HEADは、この「付箋を経由する」というワンクッションがなくなり、HEADが特定のコミットを直接指している状態です。日本語だと「HEADが切り離された状態」と訳されます。
例え話:しおりを挟まずに本を読んでいる
本を読むとき、ふつうは「しおり」を挟みます。読み進めればしおりも移動させるので、次に開いたとき続きから読めます。このしおりがブランチです。
detached HEADは、しおりを挟まずに指だけで50ページ目を押さえている状態に近いです。読むだけなら問題ありません。過去のページを確認したいだけならむしろ便利です。
問題はここで書き込みをしたとき。50ページ目にメモを書いて、そのまま指を離して別のページを開いてしまうと、「あのメモ、何ページだったっけ」となります。detached HEADでコミットしてから別のブランチに移動すると、まさにこれが起きます。コミット自体は消えていないのに、名前が付いていないので探しにくくなるわけです。
どうやってこの状態になるのか
意図的になることが多いのは、コミットハッシュやタグを直接チェックアウトしたときです。
git checkout a1b2c3d # コミットを直接指定
git checkout v1.2.0 # タグを指定
タグはブランチと違って動かない目印なので、そこにHEADを合わせると必然的にdetachedになります。「1週間前のこのコミットではバグが出ていたか?」を確かめたいとき、この移動はとても役に立ちます。
戻り方
何も変更していないなら、元のブランチに切り替えるだけで終わりです。
git switch main
ここで作業してしまい、そのコミットを残したい場合は、その場でブランチを作ってしおりを挟んでやります。
git switch -c fix/temporary
これで今いるコミットに名前が付き、以降はふつうのブランチ作業に戻ります。
すでにブランチを切らずに移動してしまった場合でも、まだ望みはあります。git reflog はHEADが辿ってきた履歴を記録しているので、そこから迷子のコミットのハッシュを見つけて、あらためてブランチを作れます。
初心者がつまずきやすいところ
一番多い誤解は「detached HEADになったらリポジトリが壊れた」と思い込むことです。壊れていません。単に立ち位置の話です。
もう一つは、警告文が長いので読み飛ばしてしまうこと。実はあのメッセージの中に「変更を残したいならブランチを作れ」という案内がちゃんと書かれています。焦らず読むと、Gitはかなり親切です。
慌ててコマンドを打つ前に git status を叩いて現状を確認する癖をつけておくと、この手の状態でパニックになりにくくなります。
このページは役に立ちましたか?