古いコミットをチェックアウトし、マスターブランチのヘッドを維持しますか?


85

現在、別のgit commit(同じブランチで...実際にはmasterブランチで!)に切り替えるために、コマンドを実行しています

git checkout ea3d5ed039edd6d4a07cc41bd09eb58edd1f2b3a

さて、私がこのgitを実行するたびに、私は今、頭が離れていることがわかります。古いコミットに移動し、同じブランチでヘッドを維持するにはどうすればよいですか?


1
そのコマンドを実行すると、HEADrefがそのコミットに変更さます。HEADが別の場所を指すようにするのは意味がありません。
Greg Hewgill 2011

gitのメッセージから私が理解していることから、それはどこにも指していません。これは望ましくありません
貪欲なエリジウム2011

1
「HEADは現在ea3d5ed ...」のような特定のコミットをチェックアウトすると、Gitが表示するメッセージは、HEADどこかを指していることを示しています。それはちょうど、他の名前がないどこかを指しています除く(以降、現時点ではHEADのgit checkout他には、コミットまたは支店名がその新しい場所にヘッドを移動します)。
Greg Hewgill 2011

与えられた答えはこれを適切に説明していますか、それとももっと明確にできることがありますか?それがあなたの質問に答えないならば、私はあなたのために私の答えを明確にしたいと思います。
ブライアンキャンベル

HEADを完全に変更せずに(たとえば、古いコミットに戻すために)別のコミットをチェックアウトする方法を探してここに来た場合:git revert --no-commit 0766c053..HEADこれを0766c053実行します。チェックアウトするコミットはどこにありますか。これはstackoverflow.com/a/21718540/525872からのものです。
Jo Liss 2017年

回答:


193

ほとんどの場合、これを行うときは、一時ブランチにチェックアウトします。

git checkout -b temp-branch-name ea3d5ed039edd6d4a07cc41bd09eb58edd1f2b3a

それから私が終わった後私はただ枝を削除します


80

そのコミットをチェックアウトするときに何をしたいかによって異なります。そのリビジョンをビルドまたはテストできるようにチェックアウトするだけであれば、取り外したヘッドで作業しても問題はありません。コミットを行う前に(git checkout masterたとえば)実際のブランチをチェックアウトすることを忘れないでください。そうすれば、どのブランチにも含まれていないコミットを作成することはありません。

ただし、その時点からさらにコミットを行う場合は、ブランチを作成する必要があります。ブランチによって参照されていないコミットを行うと、それらは簡単に失われる可能性があり、何も参照していないため、最終的にgitのガベージコレクターによってクリーンアップされます。次のコマンドを実行して、新しいブランチを作成できます。

git checkout -b newbranch ea3d5ed

視覚化に役立てるために、切り離されたヘッドでの作業とブランチでの作業の違いを示す図をいくつか示します。

masterA、B、Cの3つのコミットから始めましょう。master現在のブランチなのでHEADmasterC.をコミットしている点を、

ABC
*-*-* <-マスター<-HEAD

ここでコミットすると、gitはCを親として持つコミットを作成し(これは現在のコミットであり、HEADviaからポイントされているためmaster)、masterその新しいコミットを指すように更新されます。私たちのコミットはすべてに今あるmaster、そしてHEAD新しいのポイントが通じコミットmaster

あいうえお
*-*-*-* <-マスター<-HEAD

それでは、Bをチェックして、切り離されたを与えましょうHEAD

あいうえお
*-*-*-* <-マスター
   ^
    \ -  頭

ここではすべてが正常に機能します。すべてのファイルを調べたり、プログラムをビルドしたり、テストしたりすることができます。新しいコミットを作成することもできます。しかし、そうすると、現在のブランチがないため、その新しいコミットでブランチを指定することはできません。それを指している唯一のものはHEAD

あいうえお
*-*-*-* <-マスター
    \
     * <-HEAD
     E

後でmasterもう一度チェックアウトすることにした場合、Eを参照するものは何もありません。

あいうえお
*-*-*-* <-マスター<-HEAD
    \
     *
     E

それを参照するものがないため、見つけるのが難しい場合があり、gitは参照のないコミットを放棄されたと見なします(リベースしたり、パッチを押しつぶしたり、その他の楽しい履歴操作を行ったりすると、通常は放棄されたパッチを表します。あなたがもう気にしないこと)。一定の時間が経過すると、gitはそれをガベージと見なし、次にガベージコレクションが実行されたときに破棄されます。

したがって、ベアリビジョンをチェックアウトしてヘッドを切り離す代わりに、より多くのコミットを行う予定がある場合はgit checkout -b branch B、ブランチを作成してチェックアウトする必要があります。コミットはブランチに含まれるため、簡単に参照して後でマージできるため、コミットが失われることはありません。

あいうえお
*-*-*-* <-マスター
   ^
    \-ブランチ<-HEAD

これを忘れて、ブランチからコミットを作成する場合でも、心配する必要はありません。でヘッドリビジョンを参照するブランチを作成できますgit checkout -b branch。すでにmasterブランチに戻っており、迷子のコミットを忘れていることに気付いた場合はgit reflog、を使用して見つけることができます。これにより、HEAD過去数日間にコミットが指し示した履歴が表示されます。まだreflogに残っているものはガベージコレクションされず、通常、参照は少なくとも30日間reflogに保持されます。


古いコミットをチェックアウトすると、ヘッドが切り離される理由は私には完全にはわかりません。たぶん問題は、取り外したヘッドが何を意味するのかということですか?一方、ヘッドを外した古いコミットをチェックアウトしても失われるだけの場合、なぜ誰かがそれを行うのでしょうか?ただいじって物事を試すために?そもそも、なぜgitはそれを許可するのですか?
貪欲なエリジウム2011

5
@devoured elysiumの「切り離されたヘッド」とHEADは、コミットを指すブランチを指すのではなく、コミットのSHA-1を直接指す参照があることを意味します。あなたの頭はブランチを参照していないので、Gitは新しいコミットを追加するときにどのブランチを更新するかを知りません。回答の冒頭で説明したように、コードをビルドまたはテストするためだけに古いバージョンに戻る場合は、ヘッドを切り離してもまったく問題ありません。いつでもブランチなどに戻ることができますgit checkout master。頭が外れているときにコミットした場合にのみ問題になります。
ブライアンキャンベル

@ BrianCampbell-ブランチ(現在頭がある場所)でコミットを行った後、ブランチをBにマージし、Bをマスターにマージしますか?次に何をしますか?
amey1908 2014年

あなたの説明は私のために他の多くのものを「クリック」させました。ありがとうございました。私は今、ようやく... gitのを理解しているかもしれない
ジョー・

8

以前のコミットに戻って変更を加えずにそれを試してみたい場合は、次のことができます。

git co <previous-commit-id>

このコマンドの後、「(ブランチなし)」というブランチに移動します。

これを確認する

git br

この以前にコミットされたコードで遊んだ後、あなたはあなたがいたブランチに切り替えることができます

git co <the-branch-you-were-on>

「(ブランチなし)」は自動的に削除されます。このように、一時的なブランチを作成する必要はありません。


5

GitのHEADは、作業ディレクトリの内容を示す単なるポインタです。ブランチのヘッドではないコミットをチェックアウトしたい場合は、そのコミットを指すようにHEADをリダイレクトする必要があります。それを回避する方法はありません。そのコミットで一時ブランチを作成できますが、それでもHEADはマスターから離れるように指示されます。

それは簡単な説明です。以下の冗長性は、HEADとmasterの違いを理解するのに役立つことを願っています。

通常、次のようになります。

C ← refs/heads/master ← HEAD 
↓
B
↓
A

つまり、「Cの親はBであり、Bの親はAです。ブランチマスターはCを指しています。現在、マスターの内容を確認しています。また、コミットするとマスターが更新されます。」

これには、コミットグラフを完全に理解するために必要ないくつかの仮定が暗黙的に含まれています。つまり、コミットはその親のみを参照し、ブランチの内容は、親リンクをたどることによって到達できるコミット(およびそれらのコミットのみ)です。作業ツリーとインデックスの(変更されていない)コンテンツは、間接的(「シンボリック」)または直接(「デタッチ」)のいずれかで、HEADによって指定されたコミットに対応している必要があります。

したがって、古いコミットをチェックアウトする場合は、目的のコミットを指すようにHEADを更新する必要があります。git-checkoutまさにそれをします:

C ← refs/heads/master 
↓
B ← HEAD
↓
A

今、あなたは古いものを見ているので、あなたはあなたの後ろにあなたの枝を残しました。「切り離された頭」のアドバイスが落ち着いて教えてくれるので、それは完全に大丈夫です(私の強調):

周りを見回して実験的な変更を加えてコミットすることができます。また、別のチェックアウトを実行することで、ブランチに影響を与えることなく、この状態で行ったコミットを破棄できます。

一方、ブランチをリセットすると、必要な場所にHEADが表示されますが、効果は大きく異なります。

C
↓
B ← refs/heads/master ← HEAD
↓
A

コミットCは、マスターブランチの一部になりたくないと宣言したため、ガベージになります。

要するに、あなたがしなければならないのは、gitが「HEAD」によって何を意味するかを理解することです—それはあなたがいる場所であり、与えられたブランチがどこにあるかではありません。そして、あなたがいる場所がブランチがある場所と同じでない場合は、切り離されたHEADを使用する以外に選択肢はありません。

(HEADの脱線が続く場合は、GitHub、gitk、またはgitwebを調べて、コミット履歴を参照することもできます。)


1

質問は少し曖昧ですが、作業ツリー内のファイルを変更するだけの場合は、次のようにするだけです。

git checkout [commit|branch] -- .

その後、必要に応じて、変更をステージングし、新しいコミットを作成できます。これは時々かなり役に立ちます。


0

私はあなたの質問を理解していると思います。これが私がそれを解決するために見つけたものです。そしてそれのGUIソリューションはありません、あなたはそれを解決するためにコマンドを使うことができるだけです、そしてそれは本当に簡単です。

ステップ1:戻りたい古いコミットのタグを作成します。

タグv2.0のように

ステップ2:git checkout v2.0

これで、HEADは「v2.0」コミットを指していますが、マスターはまだ最後のコミットを指しています。

C:\Program Files\Git\doc\git\html\git-checkout.html このドキュメントはあなたを助けるかもしれません

または、git help <checkout>と入力します

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.