まず、HEADとは何か、それが切り離されたときの意味を明らかにしましょう。
HEADは、現在チェックアウトされているコミットの記号名です。HEADが切り離されていない場合(「通常の」1状況:ブランチがチェックアウトされている)、HEADは実際にはブランチの「ref」を指し、ブランチはコミットを指します。したがって、HEADはブランチに「アタッチ」されます。新しいコミットを作成すると、HEADが指すブランチは、新しいコミットを指すように更新されます。HEADはブランチを指すだけなので、自動的にフォローします。
git symbolic-ref HEAD
yields refs/heads/master
「master」という名前のブランチがチェックアウトされています。
git rev-parse refs/heads/master
yield 17a02998078923f2d62811326d130de991d1a95a
そのコミットは、masterブランチの現在のヒントまたは「頭」です。
git rev-parse HEAD
また、17a02998078923f2d62811326d130de991d1a95a
これは「シンボリック参照」であるという意味です。他の参照を介してオブジェクトを指します。
(シンボリック参照は、もともとシンボリックリンクとして実装されていましたが、シンボリックリンクを持たないプラットフォームで使用できるように、後で解釈が追加されたプレーンファイルに変更されました。)
我々は持っていますHEAD
→ refs/heads/master
→17a02998078923f2d62811326d130de991d1a95a
HEADがデタッチされると、ブランチを介して間接的に指すのではなく、直接コミットを指します。デタッチされたHEADは、名前のないブランチ上にあると考えることができます。
git symbolic-ref HEAD
失敗する fatal: ref HEAD is not a symbolic ref
git rev-parse HEAD
yields 17a02998078923f2d62811326d130de991d1a95a
これはシンボリック参照ではないため、コミット自体を直接指す必要があります。
ありますHEAD
→17a02998078923f2d62811326d130de991d1a95a
デタッチされたHEADで覚えておくべき重要なことは、それが指すコミットが他の方法で参照されていない場合(他の参照が到達できない)、他のコミットをチェックアウトすると「ぶら下がり」になるということです。最終的に、このようなダングリングコミットは、ガベージコレクションプロセスによって削除されます(デフォルトでは、コミットは少なくとも2週間保持され、HEADのreflogによって参照されることにより、より長く保持される可能性があります)。
1
デタッチされたHEADを使用して「通常の」作業を行うのはまったく問題ありません。reflogからドロップされた履歴をフィッシングしなくても済むように、自分が何をしているかを追跡する必要があります。
インタラクティブなリベースの中間ステップは、切り離されたHEADを使用して行われます(アクティブなブランチのreflogを汚染することを部分的に回避するため)。完全なリベース操作を完了すると、リベース操作の累積結果で元のブランチが更新され、HEADが元のブランチに再アタッチされます。私の推測では、リベースプロセスを完全に完了したことはありません。これにより、リベース操作によって最後に処理されたコミットを指すデタッチされたHEADが残ります。
状況から回復するには、切り離されたHEADが現在指しているコミットを指すブランチを作成する必要があります。
git branch temp
git checkout temp
(これら2つのコマンドはと省略できますgit checkout -b temp
)
これにより、HEADが新しいtemp
ブランチに再接続されます。
次に、現在のコミット(およびその履歴)を、作業が予想される通常のブランチと比較する必要があります。
git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp
(おそらく、ログオプションを試してみてください:追加-p
、--pretty=…
ログメッセージ全体を表示するために省略など)。
新しいtemp
ブランチが適切に見える場合は、master
それをポイントするように(たとえば)更新することができます。
git branch -f master temp
git checkout master
(これら2つのコマンドはと省略できますgit checkout -B master temp
)
その後、一時的なブランチを削除できます。
git branch -d temp
最後に、おそらく再確立された履歴をプッシュしたいと思うでしょう:
git push origin master
--force
リモートブランチを新しいコミットに「早送り」できない場合(つまり、ドロップしたか、既存のコミットを書き直したか、または履歴の一部を書き直した場合)は、このコマンドの最後に追加してプッシュする必要がある場合があります。
リベース操作の最中にいた場合は、おそらくクリーンアップする必要があります。ディレクトリを探して、リベースが進行中であったかどうかを確認でき.git/rebase-merge/
ます。そのディレクトリを削除するだけで、進行中のリベースを手動でクリーンアップできます(アクティブなリベース操作の目的とコンテキストを覚えていない場合など)。通常はを使用しますがgit rebase --abort
、これはおそらく回避したい追加のリセットを行います(HEADを元のブランチに戻し、元のコミットにリセットします。これにより、上記で行った作業の一部が取り消されます)。