切り離されたHEADをマスター/オリジンとどのように調整できますか?


1558

私はGitの分岐の複雑さについては初めてです。私は常に1つのブランチで作業し、変更をコミットしてから、定期的にリモートオリジンにpushします。

最近どこかで、いくつかのファイルをリセットして、コミットステージングを解除し、後でrebase -iいくつかの最近のローカルコミットを削除しました。今はよくわからない状態です。

私の作業領域でgit logは、私が期待するものを正確に示しています- 行きたくないコミットや新しいコミットなど、正しい列車に乗っています。

しかし、私はリモートリポジトリにプッシュしたところ、何が違うのですか。リベースで強制終了した2つのコミットがプッシュされましたが、ローカルにコミットされた新しいコミットはそこにはありません。

"master / origin"はHEADから切り離されていると思いますが、それが何を意味するか、コマンドラインツールでそれを視覚化する方法、およびそれを修正する方法については100%わかりません。


リベースの前にコミットをプッシュしましたか?
manojlds 2011

@manojlds:どういう意味かわかりません。リベースの少し前にプッシュしましたが、直前ではありませんでした。
Ben Zotto

以前と同様に、以前にrebase -i。で削除したコミットをプッシュしました。あなたの答えから、私はそうは思いません。
manojlds 2011

@manojlds:正解です。最近のプッシュよりも新しいコミットのみを殺しました。(私が言ったように、私はすべてが大丈夫だと思ったので、私はそれ以来プッシュしました)
ベン・ゾット

あなたがI did a reset of some files to get them out of commit staging部分的に何をしたか説明できますか?質問して申し訳ありません:)
manojlds

回答:


2521

まず、HEADとは何か、それが切り離されたときの意味を明らかにしましょう。

HEADは、現在チェックアウトされているコミットの記号名です。HEADが切り離されていない場合(「通常の」1状況:ブランチがチェックアウトされている)、HEADは実際にはブランチの「ref」を指し、ブランチはコミットを指します。したがって、HEADはブランチに「アタッチ」されます。新しいコミットを作成すると、HEADが指すブランチは、新しいコミットを指すように更新されます。HEADはブランチを指すだけなので、自動的にフォローします。

  • git symbolic-ref HEADyields refs/heads/master
    「master」という名前のブランチがチェックアウトされています。
  • git rev-parse refs/heads/masteryield 17a02998078923f2d62811326d130de991d1a95a
    そのコミットは、masterブランチの現在のヒントまたは「頭」です。
  • git rev-parse HEADまた、17a02998078923f2d62811326d130de991d1a95a
    これは「シンボリック参照」であるという意味です。他の参照を介してオブジェクトを指します。
    (シンボリック参照は、もともとシンボリックリンクとして実装されていましたが、シンボリックリンクを持たないプラットフォームで使用できるように、後で解釈が追加されたプレーンファイルに変更されました。)

我々は持っていますHEADrefs/heads/master17a02998078923f2d62811326d130de991d1a95a

HEADがデタッチされると、ブランチを介して間接的に指すのではなく、直接コミットを指します。デタッチされたHEADは、名前のないブランチ上にあると考えることができます。

  • git symbolic-ref HEAD 失敗する fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEADyields 17a02998078923f2d62811326d130de991d1a95a
    これはシンボリック参照ではないため、コミット自体を直接指す必要があります。

ありますHEAD17a02998078923f2d62811326d130de991d1a95a

デタッチされた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を元のブランチに戻し、元のコミットにリセットします。これにより、上記で行った作業の一部が取り消されます)。


6
からの興味man git-symbolic-ref:「以前は.git/HEADを指すシンボリックリンクでしたrefs/heads/master。別のブランチに切り替えたいときはそうしln -sf refs/heads/newbranch .git/HEAD、どのブランチにいるかを知りたいときはそうしましたreadlink .git/HEAD。しかし、シンボリックリンクは完全に移植可能ではありません。 、したがって、これらは非推奨になり、シンボリック参照(上記のとおり)がデフォルトで使用されます。
ドミトリーミンコフスキー2013

10
私は@AntonioSestoに同意します。ほとんどのプロジェクト(かなり大きなプロジェクトであっても)では、Gitのような気が遠くなるような複雑さは必要ありません。私の脳は、明らかに明らかに過剰に設計されたものに取り組んでいます。私はそれを必要としません、そして私はそれを望みません。
Jasper Sprengers 2015

36
これは良い答えですが、tempブランチは必要ないと思います(通常は自分のブランチを使用します)。 git branch -f master HEAD && git checkout master十分です-あなたの目標はあなたの現在の頭を維持することですが、それをと指定することmasterです。他の目標も理にかなっており、他のレシピを求めています。
エイドリアン・ラトナパラ2015年

38
長さについてガーニングコメントで笑。残りの部分は、「状況から回復するには[...]」という行に到達するまでスキャンし、そこから進みます-わかりやすい説明があり、読むことができるという裏付けがあることをメンタルにメモしながら雨の日。オプションでは、あなたを傷つけることはありません続きを読むためには、それがない給付他人に立っています。
underscore_d 2016年

5
これが私がgitを嫌う理由です。
モニカヘドネック

627

これを行うだけです:

git checkout master

または、保持したい変更がある場合は、次のようにします。

git checkout -b temp
git checkout -B master temp

57
これは危険な対応です。この回答に到達する人々にはさまざまな状態があり、「修正するためにこれを実行する」という回答は質問に回答しません。これは簡単に仕事を破壊することができます。
Archonic

15
!「git checkout master」は、取り外したヘッドがマスターの一部でない場合、すべての変更が失われる原因になります!!
Tony

3
@Blauhirnブランチではなくコミットをチェックアウトした可能性があります。ブランチはまだ同じコミットを指していますが、別の「モード」にいます。
Daniel Alexiuc 2016年

1
git reset「何をしているのか分からない場合は、中止してください」という警告が表示されます。私は最後の1週間の仕事を失ったと思って恐怖の1時間からちょうど回復しました。ありがとう!
Opus1217

1
@Archonicに同意するコマンドを盲目的に実行する前に、gitの動作を理解することが重要です。大きな答えを読まないことで時間を節約できますが、作業が失われると、さらに多くの時間を失う可能性があります。
Yusufali2205

132

私はこの問題に遭遇し、トップ投票の回答を読んだとき:

HEADは、現在チェックアウトされているコミットの記号名です。

私は思った:あはは!場合HEADcurrenltyのシンボリック名はコミットチェックアウトですが、私はに対してそれを調整することができますmasterに対してそれをリベースによってmaster

git rebase HEAD master

このコマンド:

  1. チェックアウト master
  2. からの分岐HEAD点への親のコミットを識別しますHEADmaster
  3. これらのコミットを上で再生します master

最終結果は、存在していたHEADが存在しなかったすべてのコミットmasterも存在することになりmasterます。masterチェックアウトされたままです。


リモコンについて:

私がリベースで殺したいくつかのコミットがプッシュされ、ローカルでコミットされた新しいコミットはそこにはありません。

リモート履歴は、ローカル履歴を使用して早送りすることはできなくなりました。git push -fリモート履歴を上書きするには、強制プッシュ()が必要です。共同編集者がいる場合は、通常これを調整して、全員が同じページにいるようにします。

masterリモートoriginにプッシュすると、リモート追跡ブランチorigin/masterが更新され、と同じコミットを指すようになりmasterます。


3
git:「最初に、ヘッドを巻き戻して作業を上から再生します...マスターをヘッドに早送りします。」私:「いいね!」
ベンジャミン

81

デタッチヘッドの基本的な説明については、こちらをご覧ください。

http://git-scm.com/docs/git-checkout

それを視覚化するコマンドライン:

git branch

または

git branch -a

次のような出力が得られます。

* (no branch)
master
branch1

* (no branch)ショーあなたは切り離さ頭の中にあります。

あなたはgit checkout somecommit等を行うことによってこの状態になる可能性があり、それは次のことであなたに警告するでしょう:

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

作成したコミットを保持するために新しいブランチを作成する場合は、checkoutコマンドで-bを再度使用することで(現在または後で)行うことができます。例:

git checkout -b new_branch_name

今、それらをマスターに入れるには:

実行するgit reflogか、さらにgit logはコミットを記録します。今git checkout mastergit mergeコミット。

git merge HEAD@{1}

編集:

追加するには、git rebase -i不要なコミットの削除/強制終了だけでなく、それらの編集にも使用します。コミットリストで「編集」と言うだけで、コミットを修正してgit rebase --continueからa を発行して先に進むことができます。これは、あなたがデタッチされたHEADに決して来ないことを確実にするでしょう。


ここに詳細とすばらしい情報のポインタをありがとう。明示的なマージは不要であるように見えますが、これにより、後で説明するいくつかの概念が視覚化されました。ありがとう。
ベンゾット

6
「@ {1}」は何をしますか?
ebi

35

デタッチされたコミットを独自のブランチに取得する

単に実行しgit checkout -b mynewbranchます。

次にを実行するとgit log、コミットがHEADこの新しいブランチにあることがわかります。


これを行うと、mynewbranch何かにアタッチされますか?
ベンジョン、2015年

1
はい、それは取り外したヘッドが取り付けられるはずだった場所に取り付けられます。これはまさに私が欲しかったものです。ありがとう!
ベンジョン、2015年

22

マスターブランチだけがあり、「開発」または機能に戻りたい場合は、次のようにします。

git checkout origin/develop

注:origin / developを確認してください。

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

その後

git checkout -b develop

できます :)


7
私にとってうまくいったのは「git checkout origin / develop」ではなく「git checkout develop」です。'origin / develop'を使用しても常に変更は行われず、 "HEAD detached at origin / develop"に残ります。「origin」の部分をスキップすると、すべてが修正されました。
DrStrangepork 2014

18

現在の切り離されたHEADをプッシュしたい場合は(git log前に確認してください)、次のことを試してください。

git push origin HEAD:master

切り離されたHEADをoriginのマスターブランチに送信します。プッシュが拒否された場合は、git pull origin master最初に変更元からの変更を取得してください。オリジンからの変更を気にせずに拒否された場合は、意図的にリベースしており、オリジン/マスターを現在切り離されているブランチに置き換えたい場合は、強制的に変更できます(-f)。以前のコミットにアクセスできなくなった場合は、いつでも実行git reflogしてすべてのブランチの履歴を確認できます。


変更を維持しながらマスターブランチに戻るには、次のコマンドを試してください。

git rebase HEAD master
git checkout master

参照:Git:「現在どのブランチにもありません。」変更を維持しながらブランチに戻る簡単な方法はありますか?


2
これは確かに切り離されたコミットをorigin / masterに送信します。ヘッドをローカルブランチに接続するには、次のようにします。stackoverflow.com
a/17667057

これを行うと、このリポジトリはGit LFS用に構成されていますが、パスに「git-lfs」が見つかりませんでした。Git LFSを使用したくない場合は、.git / hooks / post-checkoutを削除してこのフックを削除します。
user2568374 2018年

16

検索中にこの質問が見つかりました You are in 'detached HEAD' state.

私がここにたどり着くまでに行ったことを分析したところ、過去の自分と比べて、間違いを犯したことがわかりました。

私の通常の流れは:

git checkout master
git fetch
git checkout my-cool-branch
git pull

今回は私がやった:

git checkout master
git fetch
git checkout origin/my-cool-branch
# You are in 'detached HEAD' state.

問題は、私が誤って行ったことです。

git checkout origin/my-cool-branch

のではなく:

git checkout my-cool-branch

(私の状況では)修正は、上記のコマンドを実行してフローを続行することでした:

git checkout my-cool-branch
git pull

11

以下は私のために働いた(ブランチマスターのみを使用して):

git push origin HEAD:master
git checkout master        
git pull

最初のものは、切り離されたHEADをリモートオリジンにプッシュします。

2つ目はブランチマスターに移動します。

3つ目は、ブランチマスターに接続されたHEADを回復します。

プッシュが拒否された場合、最初のコマンドで問題が発生する可能性があります。しかし、これはデタッチされたヘッドの問題ではなくなりますが、デタッチされたヘッドはいくつかのリモートの変更を認識していないという事実についてです。


動作しませんでした。このリポジトリはGit LFS用に構成されていますが、パスに「git-lfs」が見つかりませんでした。Git LFSを使用したくない場合は、.git / hooks / pre-pushを削除してこのフックを削除します。そして、あなたは現在ブランチにいません。マージするブランチを指定してください。
user2568374 2018年

11

今日この問題に遭遇しましたが、次のようにして解決したと確信しています。

git branch temp
git checkout master
git merge temp

これを行う方法を見つけたとき、私は自分の仕事用コンピューターにいたのですが、今、自分のパソコンでも同じ問題に直面しています。ですから、仕事用のコンピュータに戻った月曜日まで、私がどのようにしたかを正確に確認するまで待たなければなりません。


@StarShine Kenorbが修正しました。これで、切り離されたコミットが新しいブランチ、tempに保存され、マスターに切り替わり、tempがマスターにマージされます。
Cees Timmerman、2016年

なぜpplがこれに反対票を投じているのかわかりません。問題の統計情報は修正されましたが、delete tempブランチコマンドを含めることをお勧めします。
GlassGhost 2016年

8

HEADが良好な状態であると完全に確信している場合:

git branch -f master HEAD
git checkout master

マスターが起源から分岐しているため、おそらく起源にプッシュできません。他のユーザーがリポジトリを使用していないことが確実な場合は、強制的にプッシュできます。

git push -f

他の誰も使用していない機能ブランチにいる場合に最も役立ちます。


6

あなたがしなければならないのは、 'git checkout [branch-name]'だけです。ここで、[branch-name]は、分離ヘッド状態になった元のブランチの名前です。(asdfasdfから切り離された)が消えます。

たとえば、ブランチ「dev」でコミットasdfasd14314->をチェックアウトします。

'git checkout asdfasd14314'

あなたは今、分離した頭の状態です

'git branch'は次のようなリストを表示します->

* (detached from asdfasdf)
  dev
  prod
  stage

しかし、切り離されたヘッド状態から抜けて、devに戻るには->

'git checkout dev'

そして 'git branch'がリストされます->

* dev
  prod
  stage

しかし、それはもちろん、デタッチされたヘッドの状態からの変更を保持するつもりはないが、私がこれを行うのは、変更を加えるつもりではなく、以前のコミットを見ることだけである場合です。


6

クリスが指摘したように、私は次のような状況にありました

git symbolic-ref HEAD 失敗する fatal: ref HEAD is not a symbolic ref

ただしgit rev-parse refs/heads/master、私が回復できる場所からの適切なコミットを指していた(私の場合、最後のコミットであり、git show [SHA]

その後、めちゃくちゃなことをたくさんやったが、直ったように見えるのは、

git symbolic-ref HEAD refs/heads/master

そして頭が再装着!


1
ありがとう!頭が離れてしまった。私はそれをマスターに追いつくことができましたが、彼らはたまたまコミットを指しているマスターを指すのではなく、たまたま同じコミットを指しているだけです。良いヒント= D
RagingRoosevelt 2018年

4

する代わりに git checkout origin/master

するだけ git checkout master

次にgit branch、ブランチを確認します。


4

今日、この問題がありました。サブモジュールを更新しましたが、どのブランチにもありませんでした。私はすでにコミットしていたので、隠しておいて、チェックアウトして、元に戻すことはできませんでした。結局、取り外された頭のコミットをチェリーピックした。だから私がコミットした直後(プッシュが失敗したとき)、私はしました:

git checkout master
git cherry-pick 99fe23ab

私の考えは次のとおりです。私は離れた頭の上にいますが、マスターになりたいです。切り離された状態がマスターとそれほど変わらないと仮定すると、マスターにコミットを適用できれば、設定されます。これがまさにチェリーピックです。


3

マスターの上でいくつかのコミットを行い、masterそこで「後方マージ」したい場合(つまり、masterをポイントしたい場合HEAD)、ワンライナーは次のようになります:

git checkout -B master HEAD
  1. これにより、masterが存在する場合でも、という名前の新しいブランチが作成されます(これは移動のようなmasterものであり、それが目的です)。
  2. 新しく作成されたブランチはHEAD、現在の場所であるを指すように設定されています。
  3. 新しいブランチがチェックアウトされたので、master後でオンになります。

これは、サブリポジトリの場合に特に便利であることがわかりました。サブリポジトリも、たまに切り離された状態になっていることがあります。


3

同じ問題が発生しましたが、次の手順を実行することで解決しました。

変更を維持する必要がある場合

  1. まず、git checkout masterコマンドを実行してマスターブランチに戻る必要があります。
  2. 変更を維持する必要がある場合は、実行git checkout -b changesして git checkout -B master changes

変更が必要ない場合

  1. 追跡されていないすべてのファイルをブランチから削除するには、を実行しgit clean -dfます。

  2. 次に、リポジトリ内のすべてのステージングされていない変更をクリアする必要があります。そのためには、実行する必要がありますgit checkout --

  3. 最後に、git checkout masterコマンドを使用してブランチをマスターブランチに戻す必要があります。


3

私にとっては、ローカルブランチを削除するのと同じくらい簡単でした。プッシュしたいローカルコミットがなかったからです。

だから私はしました:

git branch -d branchname

そして、もう一度ブランチをチェックアウトします:

git checkout branchname

1

私がいないときに変更を加えたmaster(つまりHEAD、真上で切り離されてmasterおり、間にコミットがない)場合、スタッシングが役立つ可能性があります。

git stash # HEAD has same content as master, but we are still not in master
git checkout master  # switch to master, okay because no changes and master
git stash apply  # apply changes we had between HEAD and master in the first place

1

簡単に言うと、切り離されたHEAD状態は、ブランチのHEAD(またはチップ)にチェックアウトされていないこと意味します

例を理解する

ほとんどの場合の分岐は、次のような複数のコミットのシーケンスです。

コミット1: マスター-> branch_HEAD(123be6a76168aca712aea16076e971c23835f8ca)

コミット2: マスター-> 123be6a76168aca712aea16076e971c23835f8ca-> branch_HEAD(100644a76168aca712aea16076e971c23835f8ca)

上記のように一連のコミットの場合、ブランチは最新のコミットを指します。したがって、その場合、123be6a76168aca712aea16076e971c23835f8caをコミットするようにチェックアウトすると、ブランチのHEADが100644a76168aca712aea16076e971c23835f8caを指すため、分離ヘッド状態になります。を、技術的にはブランチのないHEADでチェックアウトさ。したがって、分離したHEAD状態になります。

理論的説明

このブログでは、Gitリポジトリがコミットツリーであることを明確に示しています。各コミットは、その先祖を指す各コミットポインターが更新され、各ブランチへのこれらのポインターは.git / refsサブディレクトリに格納されます。タグは.git / refs / tagsに保存され、ブランチは.git / refs / headsに保存されます。いずれかのファイルを見ると、各タグが40文字のコミットハッシュを持つ単一のファイルに対応していることがわかります。@ Chris Johnsenと@Yaroslav Nikitenkoによって上記で説明したように、これらの参照を確認できます。


0

私は本当にばかげた状態になりました、他の誰もがこれが役立つとは思えません...

git ls-remote origin
0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b        HEAD
6f96ad0f97ee832ee16007d865aac9af847c1ef6        refs/heads/HEAD
0d2ab882d0dd5a6db93d7ed77a5a0d7b258a5e1b        refs/heads/master

私は最終的にこれで修正しました

git push origin :HEAD

0

これは私にとって完璧に機能しました:

1. git stashローカルの変更を保存する

変更を破棄したい場合、
git clean -df
git checkout -- .
git cleanはすべての追跡されていないファイルを削除し(警告:.gitignoreに直接記述されている無視されたファイルは削除しませんが、フォルダーにある無視されたファイルを削除する可能性があります)、git checkoutはすべてのステージングされていない変更をクリアします。

2. git checkout masterメインブランチに切り替える(マスターを使用する場合)
3. git pullマスターブランチから最後のコミットをプルする
4. git statusすべてが適切に表示されることを確認する

On branch master
Your branch is up-to-date with 'origin/master'.

0

私の場合、を実行git statusしたところ、作業ディレクトリに追跡されていないファイルがいくつかあることがわかりました。

リベースを機能させるには、それらをクリーンアップする必要がありました(私はそれらを必要としなかったため)。


0

EclipseでEGitを使用している場合:マスターがメインの開発ブランチであると想定します

  • ブランチへの変更をコミットします。通常は新しいブランチです。
  • 次にリモコンから引っ張る
  • 次に、プロジェクトノードを右クリックし、チームを選択して、履歴の表示を選択します
  • 次にマスターを右クリックし、チェックアウトを選択します
  • Eclipseが指示した場合、2つのマスターが1つ、ローカルが1つ、リモートが1つ、リモートを選択します。

この後、オリジンマスターに再接続できるはずです。


-1

私も同じ問題を抱えていました。私は自分の変更を隠し、 git stashローカルのブランチを以前のコミットにハードリセットしました(それが原因だと思っていました)、それからaを実行しましたがgit pull、今はそのヘッドが切り離されていません。git stash applyもう一度変更することを忘れないでください。


-2
git checkout checksum  # You could use this to peek previous checkpoints
git status # You will see HEAD detached at checksum
git checkout master # This moves HEAD to master branch
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.