私は Git のブランチの複雑さに慣れていません。常に 1 つのブランチで作業し、変更をコミットしてから、定期的にリモートの origin にプッシュします。
最近、いくつかのファイルをコミット ステージングから削除するためにリセットし、その後、rebase -i
最近のローカル コミットをいくつか削除するために を実行しました。現在、よくわからない状態になっています。
私の作業領域には、git log
まさに期待どおりの結果が表示されています。つまり、削除したくないコミットや新しいコミットなど、正しい手順で作業が進んでいるということです。
しかし、リモート リポジトリにプッシュしたところ、内容が異なっていました。リベースで削除したコミットのいくつかがプッシュされ、ローカルでコミットされた新しいコミットはそこにありませんでした。
「master/origin」は HEAD から切り離されていると思いますが、それが何を意味するのか、コマンドライン ツールでそれを視覚化する方法、そしてそれを修正する方法が 100% 明確ではありません。
ベストアンサー1
まず、明確にしておきましょうHEADとは何かそしてそれが切り離されたときに何を意味するのか。
HEAD は現在チェックアウトされているコミットのシンボル名です。HEAD がデタッチされていない場合 (「通常」の状況: ブランチがチェックアウトされている)、HEAD は実際にはブランチの「ref」を指し、ブランチはコミットを指します。つまり、HEAD はブランチに「アタッチ」されます。新しいコミットを行うと、HEAD が指しているブランチは新しいコミットを指すように更新されます。HEAD はブランチを指すだけなので、自動的に追従します。
git symbolic-ref HEAD
refs/heads/master
「master」という名前のブランチがチェックアウトされます。git rev-parse refs/heads/master
yield17a02998078923f2d62811326d130de991d1a95a
そのコミットは、マスター ブランチの現在の先端または「ヘッド」です。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
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
(ログ オプションを試してみるとよいでしょう: add 、ログ メッセージ全体を表示するには-p
leave offなど)--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 を元のブランチに戻して元のコミットにリセットするため、上で行った作業の一部が元に戻ってしまいます)。