【Git】detached HEAD状態から元の作業ブランチに戻す方法|7シナリオ診断と救済・予防完全ガイド

【Git】detached HEAD状態から元の作業ブランチに戻す方法 Git

Gitで過去のコミットやタグをcheckoutすると、git statusに次のような警告が出ることがあります。

detached HEADの警告
$ git status
HEAD detached at a1b2c3d

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.

このdetached HEAD(分離HEAD)状態は「HEADがどのブランチにも属していない」ことを意味し、放置してブランチを切り替えるとこの状態で積んだコミットが迷子になる危険があります。幸い、慌てなければgit switchgit reflogで簡単に復帰できます。

この記事では、detached HEADの正体と7つの発生シナリオ、状況別の復帰手順、迷子コミットの救済方法、そしてそもそも陥らないための予防策まで実務で役立つ形でまとめます。bisect・worktree・submoduleといったdetached HEADが正常動作の一部である特殊ケースも扱います。

この記事で学べること

  • detached HEADが発生する7つの代表シナリオ
  • git statusgit reflogによる状況診断
  • 作業がない場合の復帰(git switch -・ブランチ指定)
  • detached中のコミットを救済する手順(git switch -cでブランチ化)
  • bisect・worktree・submoduleでの想定外の挙動
  • 迷子コミットをreflogから復元する方法
  • そもそもdetachedにならないための運用(git switch -c徹底)
スポンサーリンク

detached HEADの正体

GitのHEADは「現在作業中のコミット」を指すポインタです。通常はrefs/heads/mainのようなブランチ名を指しています。detached HEAD状態では、ブランチ名を経由せずにコミットSHAを直接指している状態になります。

HEADの中身を見る
# 通常状態:HEAD はブランチを指す
cat .git/HEAD
# → ref: refs/heads/main

# detached 状態:HEAD はコミットSHAを直接指す
cat .git/HEAD
# → a1b2c3d4e5f6...

# 一発で判定
git symbolic-ref -q HEAD
# 通常: refs/heads/main
# detached: 何も表示されず終了コード1

detachedでも「悪い状態」ではない

  • 過去の状態を確認するだけ/古いタグを試すには普通の操作
  • コミットを積まずに元ブランチへ戻れば失うものはない
  • bisectやworktreeでは意図的にdetachedにする
  • 危険なのは「detached中に作業してブランチ切替してしまう」こと

ポイント:「detached HEADになった」だけで慌てる必要はありません。警告メッセージ自体は情報提供が目的です。作業していなければgit switch -で即復帰できるので、「発生=事故」ではなく「作業したときだけ注意」と考えましょう。

detached HEADが発生する7つのシナリオ

意図的・意図せず問わず、detached HEADに入るタイミングは複数あります。自分の状況を特定すると対処が決めやすくなります。

シナリオ トリガー
① コミットSHAを直接checkout git checkout a1b2c3d
② タグをcheckout git checkout v1.2.0
③ 明示的に--detach git switch --detach main
④ リモート追跡ブランチを直接checkout git checkout origin/main
⑤ bisect実行中 git bisect start以降の自動checkout
⑥ submodule/worktreeの初期化 git submodule update --init
⑦ shallow cloneの一部環境 CI/自動化でdepth=1 cloneした結果

意図的 vs 意図しないdetached

  • 意図的(bisect・worktree・submodule等):普通に使うものなので心配不要
  • 意図しない(SHA/タグ/リモート直接checkout):警告を読んで対処
  • 多くの「困った」ケースは①〜④の意図しないdetached

STEP 0:現在の状態を診断する

状況確認コマンド
# detached かどうか
git status
# "HEAD detached at XXX" が出れば detached

# HEADの生情報
git symbolic-ref -q HEAD
# 何も表示されなければ detached

# どこから来たか(直前のブランチ)
git reflog -10
# 出力例:
# a1b2c3d HEAD@{0}: checkout: moving from main to a1b2c3d
# e4f5g6a HEAD@{1}: commit: 前のcommit
# i7j8k9l HEAD@{2}: checkout: moving from feature to main

# detached中にコミットしているかチェック
git log --oneline HEAD ^$(git branch --format='%(refname:short)' | tr '\n' ' ')
# 出力があれば、どのブランチにも紐づかないコミット

診断チェックリスト

  • git statusで”HEAD detached”表示 → detached確定
  • git reflogで元のブランチを特定
  • detached以降にコミットがあるか確認
  • 無ければ単純に戻るだけ、あれば保全してから戻る

復帰①:作業していない場合は1コマンドで戻る

detached HEADの状態でコミットを一切作っていなければ、ブランチに戻るだけで終わります。迷ったらgit switch -で直前ブランチに戻るのが最速です。

元ブランチに戻るコマンド
# 直前のブランチに戻る(もっとも簡単)
git switch -
# または
git checkout -

# ブランチ名を指定して戻る
git switch main
git switch feature/login

# 戻った後の状態確認
git status
# → On branch main

ポイント:git switch -はシェルのcd -のように「1つ前のブランチ」に戻ります。detached HEAD状態のように「ブランチから来た」場合は便利。ただしcheckout履歴が長くなっていると正確に動かないので、確実に戻るならブランチ名を明示しましょう。

復帰②:detached中にコミットした場合は救済が必要

detached HEAD中にgit commitを実行していた場合、そのコミットはどのブランチにも紐づいていない状態です。そのまま他のブランチに切り替えると、コミットSHAが参照を失い、最終的にGCで消滅します。先にブランチ化して保全しましょう。

detached中のコミットを保全する
# 現在位置(コミット積んだ先)を新ブランチとして固定
git switch -c rescue/my-work

# これでdetachedコミットはrescue/my-workブランチの履歴になった
git log --oneline -5

# 必要に応じてpushで保全
git push -u origin rescue/my-work

# その後、元のブランチへ安心して戻れる
git switch main

禁止:detached中にコミットしたままgit switch main等で別ブランチに切り替えると、Gitは警告を出しますが無視するとコミットが迷子状態になります。必ずgit switch -c rescue/xxxでブランチ化してから移動してください。

警告を見逃して切り替えてしまった場合

reflogから迷子コミットを救出
# 過去のHEAD履歴からSHAを探す
git reflog -20

# detached時のコミットSHAを特定したら
git switch -c rescue/lost-work <SHA>

# 直後なら簡単だが、reflog期限(90日)を超えると救済不可

迷子ブランチ/commit全般の救済は誤ってmaster/mainを削除したときの復旧方法も参考になります。

特殊ケース:意図的detachedとその抜け方

bisect中のdetached HEAD

git bisectでバグ発生コミットを探す時、Gitは自動でdetached HEADにします。これは正常な動作で、bisect終了時に元のブランチに戻ります。

bisect中の作法
# bisect 開始
git bisect start
git bisect bad HEAD
git bisect good v1.0.0
# → detachedで中間コミットにcheckoutされる

# 動作確認して good/bad を伝える
git bisect good
# または
git bisect bad

# bisect 終了して元ブランチに戻る
git bisect reset

bisectの詳細はbisectでバグを仕込んだコミットを特定する方法を参照。

worktreeのdetached HEAD

worktree add –detach
# 指定コミットでworktreeを作る(detached)
git worktree add --detach ../review-pr a1b2c3d

# そのworktreeに移動
cd ../review-pr
git status
# HEAD detached at a1b2c3d

# そのまま参照用に使うならそれで良い
# 作業するならブランチを切る
git switch -c scratch/review

submodule初期化時

submoduleのdetached
# submoduleを初期化すると各submoduleがdetachedになる
git submodule update --init --recursive

# submodule内に入って作業するなら
cd path/to/submodule
git switch main   # またはsubmoduleの開発ブランチに

# submoduleは各々独立したリポジトリ

意図的detachedの特徴

  • bisect:終了時にbisect resetで自動復帰
  • worktree:新ブランチを切るかworktree削除で対処
  • submodule:内部で作業する前にブランチ切替
  • これらは「正常動作」なのでエラーと混同しない

そもそもdetached HEADに陥らないために

detachedに入る最大の経路は「過去コミット/タグをcheckout」です。最初からブランチ化しながら移動すれば、detached状態を経由せずに済みます。

安全な派生パターン
# 過去コミットから作業するなら最初からブランチ化
git switch -c scratch/old-check a1b2c3d

# タグから始める場合も同じ
git switch -c hotfix/v1.2.1 v1.2.0

# リモート追跡ブランチから
git switch -c review/pr-42 origin/feature/pr-42

# 単に履歴を見るだけなら switch せずに show / log でOK
git show a1b2c3d
git log -p a1b2c3d
git log --graph --all --oneline

ポイント:「見るだけ」ならgit showgit log、「作業するかも」ならgit switch -cでブランチ化、が黄金ルール。git checkoutでSHAやタグを指定して移動する習慣は事故の温床なので、今からswitch -c中心に切り替えましょう。

過去コミット起点のブランチ作成の詳細は過去のコミットから新しいブランチを作り作業をやり直す方法を参照してください。

便利なエイリアス

detached予防のエイリアス
# 検証用scratch branchをSHAから切る
git config --global alias.scratch '!f() { git switch -c "scratch/$(date +%Y%m%d-%H%M)" "$1"; }; f'

# 使用例
git scratch a1b2c3d
# → scratch/20260101-1530 という使い捨てブランチを自動で作る

実践シナリオ

シナリオ① タグをcheckoutしたら警告が出た

見るだけなら即戻る
git checkout v1.2.0
# HEAD detached at v1.2.0

# 中身を見るだけで作業しないなら直接戻る
git switch -
# または
git switch main

シナリオ② detached中に2〜3コミット積んでしまった

救済ブランチを作る
# 現在位置確認
git log --oneline -5

# 救済ブランチを切って保全
git switch -c rescue/my-experiments

# pushで保全(お好みで)
git push -u origin rescue/my-experiments

# 必要なコミットをmainへ移す場合
git switch main
git cherry-pick <SHA>

シナリオ③ 切り替えてしまった後でdetachedコミットを思い出した

reflogで救出
git reflog --all -30
# 出力からdetached時のSHAを特定
# a1b2c3d HEAD@{3}: commit: 消したくないコミット

# SHAからブランチ化
git switch -c rescue/recovered a1b2c3d

シナリオ④ bisect中に誤ってgit switchしてしまった

bisectを正しく終わらせる
# まず元のブランチに戻る
git bisect reset
# → bisect開始前のブランチに自動で戻る

# bisect情報を確認
git bisect log

やってはいけない落とし穴

警告を無視してブランチ切替

detached状態でコミットを積んだ後にgit switch mainすると、GitはWarning: you are leaving N commits behind, not connected to any of your branchesと警告を出します。無視すると迷子コミットになり、最終的にGCで削除されます。必ずgit switch -c rescue/xxxで保全してから移動。

reflogを当てにしすぎる

reflogは既定90日で自動clean upされます。長期間経って気付いたdetachedコミットは復元できないことがあります。大事な作業は即座にブランチ化&pushで保全するのが鉄則です。

bisect中に自分でcheckoutする

bisect中はGitが自動でHEADを動かしています。途中で手動git checkoutgit switchするとbisectのプロセスが壊れます。終わらせたいならgit bisect resetを使ってください。

submodule内でdetached中に開発して親リポを参照する

submodule内でdetached状態のままcommit&pushすると、親リポは「detached時点のSHA」を参照したままになります。submodule内で作業する前に必ずブランチに切替え、作業後は親リポでgit add <submodule>+commitで参照SHA更新を。

worktreeのdetachedを消さずに放置

git worktree add --detachで作った検証用worktreeを使い終わった後、削除せずに放置すると、.gitにworktree情報が溜まります。使い終わったらgit worktree remove <path>で明示的に削除しましょう。

よくある質問

Qdetached HEADは危険な状態?
A状態自体は危険ではなく、Gitの正常な機能です。危険になるのは「コミットを作った後にブランチ化せず切替してしまう」場合のみ。見るだけならgit switch -ですぐ戻れます。
Q元のブランチ名を忘れた
Agit reflogで履歴を見ればcheckout: moving from X to Yという行がHEADの移動を示しています。そこからブランチ名が特定できます。git switch -(直前ブランチに戻る)も有効です。
Qdetachedコミットを本線に取り込みたい
Aまずブランチ化してgit switch -c rescue/xxx、その後本線へマージまたはcherry-pickで必要なコミットを取り込みます。detached状態で直接mergeすることはできません。
Qdetachedコミットをpushできる?
A直接は推奨されません。先にgit switch -cでブランチ化してからgit push -u origin <branch>します。git push origin HEAD:refs/heads/new-branchで直接pushすることも技術的に可能ですが、ブランチ化してからpushする方が分かりやすく事故も防げます。
Qbisectが終わった後もdetachedのまま
Agit bisect resetを実行してください。開始前のブランチに自動的に戻ります。実行し忘れると元のブランチに戻れない状態になります。
Qgit switch – と git switch @{-1} は同じ?
A実質同じです。-@{-1}のショートカットで、「1つ前のブランチ参照」を意味します。git switch @{-2}のようにさらに前に戻ることもできます。
QVS CodeやGUIツールでdetachedに気付きにくい
Aステータスバーのブランチ表示が「HEAD (detached)」「(detached at xxxx)」となります。JetBrainsやSourceTreeも同様の表示。GUIでもdetachedは視認できるので、違和感を感じたらgit statusで確認する習慣を付けましょう。

関連記事

まとめ

  • detached HEADはHEADがブランチではなくコミットSHAを直接指している状態
  • 発生は7パターン:コミットSHA/タグ/--detach/リモート直指定/bisect/worktree/submodule等
  • 作業していなければgit switch -で即復帰
  • コミットを積んでいたらgit switch -c rescue/xxxで必ずブランチ化
  • 切替後に気付いたらgit reflogから90日以内に救済可
  • bisect/worktree/submoduleは意図的detachedなので通常の操作で終了させる
  • 予防:過去コミット起点の作業は最初からgit switch -c scratch/xxx <SHA>

detached HEADは「怖いエラー」ではなく、Gitが「特別な状態にいます」と教えてくれる親切な警告です。見るだけなら即戻り、作業してしまったらブランチ化で保全——この2つを覚えておけば事故は起きません。さらに「過去コミットに移動する時は最初からgit switch -c」という習慣を付ければ、そもそもdetachedに入る回数が激減します。reflogという強力な救済手段もあるので、落ち着いて手順を踏めば必ずリカバーできます。