Frage Wie kann ich losgelöste HEAD mit Master / Herkunft abgleichen?


Ich bin neu in den verzweigten Komplexitäten von Git. Ich arbeite immer an einem einzelnen Zweig und begehe Änderungen und drehe dann regelmäßig zu meinem entfernten Ursprung.

Irgendwann habe ich einige Dateien zurückgesetzt, um sie aus dem Commit-Staging zu entfernen rebase -i um ein paar kürzliche lokale Verpflichtungen loszuwerden. Jetzt bin ich in einem Zustand, den ich nicht ganz verstehe.

In meinem Arbeitsbereich, git log zeigt genau das, was ich erwarten würde-- Ich bin im richtigen Zug mit den Commits, die ich nicht gehen wollte, und neuen da, etc.

Aber ich schob mich einfach zum Remote-Repository, und was dort ist, ist anders-- ein paar der Commits, die ich in der Rebase getötet hatte, wurden gedrängt, und die neuen, die lokal begangen wurden, sind nicht da.

Ich denke, dass "Master / Ursprung" von HEAD getrennt ist, aber ich weiß nicht 100%, was das bedeutet, wie man es mit den Befehlszeilenwerkzeugen visualisiert und wie man es repariert.


1274
2018-04-24 17:51


Ursprung


Antworten:


Lasst uns zuerst klären Was HEAD ist und was es bedeutet, wenn es losgelöst ist.

HEAD ist der symbolische Name für das aktuell ausgecheckte Commit. Wenn HEAD nicht abgelöst ist (das "normale"1 Situation: Sie haben einen Zweig ausgecheckt), HEAD zeigt tatsächlich auf einen Zweig "ref" und der Zweig zeigt auf das Commit. HEAD wird also an einen Zweig "angehängt". Wenn Sie ein neues Commit durchführen, wird der Zweig, auf den HEAD zeigt, aktualisiert, um auf das neue Commit zu zeigen. HEAD folgt automatisch, da es nur auf den Zweig zeigt.

  • git symbolic-ref HEAD Erträge refs/heads/master
    Der Zweig namens "Master" ist ausgecheckt.
  • git rev-parse refs/heads/master Ausbeute 17a02998078923f2d62811326d130de991d1a95a
    Dieser Commit ist der aktuelle Tipp oder "Kopf" des Master-Zweiges.
  • git rev-parse HEAD gibt auch nach 17a02998078923f2d62811326d130de991d1a95a
    Dies ist es, was es bedeutet, ein "symbolischer Verweis" zu sein. Es zeigt auf ein Objekt durch eine andere Referenz.
    (Symbolische Referenzen wurden ursprünglich als symbolische Links implementiert, später aber in einfache Dateien mit zusätzlicher Interpretation umgewandelt, so dass sie auf Plattformen ohne symbolische Links verwendet werden konnten.)

Wir haben HEAD → refs/heads/master → 17a02998078923f2d62811326d130de991d1a95a

Wenn HEAD losgelöst ist, zeigt es direkt auf einen Commit - anstatt indirekt über einen Zweig auf einen zu zeigen. Du kannst dir einen abgetrennten HEAD als einen unbenannten Ast vorstellen.

  • git symbolic-ref HEAD scheitert mit fatal: ref HEAD is not a symbolic ref
  • git rev-parse HEAD Erträge 17a02998078923f2d62811326d130de991d1a95a
    Da es kein symbolischer Verweis ist, muss es direkt auf das Commit selbst verweisen.

Wir haben HEAD → 17a02998078923f2d62811326d130de991d1a95a

Die wichtige Sache, die man sich bei einem abgetrennten HEAD merken sollte, ist, dass, wenn das Commit, auf das es zeigt, ansonsten nicht referenziert wird (kein anderer Ref kann es erreichen), wird es "baumeln", wenn man einen anderen Commit auscheckt. Eventuell werden solche dangling commits durch den Garbage-Collection-Prozess bereinigt (standardmäßig werden sie für mindestens 2 Wochen aufbewahrt und können länger aufbewahrt werden, indem sie vom HEAD-Reflog referenziert werden).

1 Es ist vollkommen in Ordnung, "normale" Arbeit mit einem abgetrennten HEAD zu machen, man muss nur den Überblick behalten, was man tut, um zu vermeiden, dass die verlorene Historie aus dem Reflog herausgefischt werden muss.


Die Zwischenschritte einer interaktiven Rebase werden mit einem abgetrennten HEAD durchgeführt (teilweise, um den Reflog des aktiven Zweiges nicht zu verschmutzen). Wenn Sie die vollständige Umbuchen-Operation abgeschlossen haben, wird Ihre ursprüngliche Verzweigung mit dem kumulativen Ergebnis der Umbuchen-Operation aktualisiert und HEAD an die ursprüngliche Verzweigung wieder angehängt. Meine Vermutung ist, dass Sie den Rebase-Prozess nie vollständig abgeschlossen haben; Dies wird Sie mit einem abgetrennten HEAD verlassen, der auf das Commit zeigt, das zuletzt von der Rebase-Operation verarbeitet wurde.

Um Ihre Situation wiederherzustellen, sollten Sie einen Zweig erstellen, der auf den Commit verweist, auf den Ihr abgetrennter HEAD momentan zeigt:

git branch temp
git checkout temp

(Diese beiden Befehle können als abgekürzt werden git checkout -b temp)

Dadurch wird der HEAD an den neuen angeschlossen temp Ast.

Als Nächstes sollten Sie das aktuelle Commit (und dessen Verlauf) mit dem normalen Zweig vergleichen, für den Sie erwartet haben zu arbeiten:

git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp

(Sie werden wahrscheinlich mit den Protokolloptionen experimentieren wollen: hinzufügen -pGeh weg --pretty=… um die gesamte Log-Nachricht zu sehen, usw.)

Wenn du neu bist temp der Zweig sieht gut aus, möchten Sie möglicherweise aktualisieren (z. B.) master darauf hinweisen:

git branch -f master temp
git checkout master

(Diese beiden Befehle können als abgekürzt werden git checkout -B master temp)

Sie können dann die temporäre Verzweigung löschen:

git branch -d temp

Schließlich werden Sie wahrscheinlich die wiederhergestellte Geschichte fortsetzen wollen:

git push origin master

Möglicherweise müssen Sie hinzufügen --force an das Ende dieses Befehls zu drücken, wenn die Remote-Zweigstelle kann nicht "Fast-forward" an die neue Festschreibung (d. h. Sie fallen gelassen, oder einige vorhandene Commit neu geschrieben oder anders ein bisschen Geschichte geschrieben).

Wenn Sie sich gerade in einer Rebase-Operation befinden, sollten Sie diese wahrscheinlich bereinigen. Sie können überprüfen, ob eine Rebase in Bearbeitung war, indem Sie nach dem Verzeichnis suchen .git/rebase-merge/. Sie können die laufende Rebase manuell bereinigen, indem Sie nur dieses Verzeichnis löschen (z. B. wenn Sie sich nicht mehr an den Zweck und den Kontext der aktiven Rebase-Operation erinnern). Normalerweise würden Sie verwenden git rebase --abort, aber das führt ein zusätzliches Zurücksetzen aus, das Sie wahrscheinlich vermeiden möchten (es verschiebt HEAD zurück in den ursprünglichen Zweig und setzt es zurück auf das ursprüngliche Commit, wodurch einige der oben ausgeführten Arbeiten rückgängig gemacht werden).


2160
2018-04-24 19:56



Mach einfach folgendes:

git checkout master

Oder, wenn Sie Änderungen haben, die Sie behalten möchten, tun Sie Folgendes:

git checkout -b temp
git checkout -B master temp

512
2017-09-18 07:23



Ich bin auf dieses Problem gestoßen und als ich in der obersten Antwort die Antwort gelesen habe:

HEAD ist der symbolische Name für das aktuell ausgecheckte Commit.

Ich dachte: Ah-ha! Ob HEAD ist der symbolische Name für den aktuellen Checkout Commit, mit dem ich ihn abgleichen kann master indem wir es gegen sie ablehnen master:

git rebase HEAD master

Dieser Befehl:

  1. Checkt aus master
  2. identifiziert die Eltern-Commits von HEAD zurück zum Punkt HEAD divergierte von master
  3. spielt diese Commits auf master

Das Endergebnis ist, dass alle Commits, die in waren HEAD aber nicht master sind dann auch in master. master bleibt ausgecheckt.


Bezüglich der Fernbedienung:

ein paar der Commits, die ich in der Rebase getötet hatte, wurden gedrängt, und die Neuen, die ich vor Ort engagiert habe, sind nicht da.

Die Remote-Historie kann nicht mehr mit Ihrer lokalen Historie weitergeleitet werden. Sie müssen erzwingen (git push -f) um den Remote-Verlauf zu überschreiben. Wenn Sie Kollaborateure haben, ist es normalerweise sinnvoll, dies mit ihnen zu koordinieren, damit alle auf derselben Seite sind.

Nach dem Drücken master zu entfernt origin, Ihre Remote-Tracking-Filiale origin/master wird aktualisiert, um auf denselben Commit wie zu zeigen master.


97
2017-08-02 03:10



Sehen Sie sich hier die grundlegende Erklärung für den abgelösten Kopf an:

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

Befehlszeile, um es zu visualisieren:

git branch

oder

git branch -a

Sie erhalten die Ausgabe wie folgt:

* (no branch)
master
branch1

Das * (no branch) zeigt, dass Sie sich in distanziertem Kopf befinden.

Du hättest in diesen Zustand kommen können, indem du einen git checkout somecommit usw. und es hätte dich mit folgendem gewarnt:

Sie befinden sich im Status 'Getrennter Kopf'. Sie   kann sich umsehen, experimentieren   Änderungen und verpflichten sie, und Sie können   Verwerfen Sie alle Commits, die Sie dabei machen   Zustand ohne Auswirkungen auf Zweige   indem Sie eine andere Kasse ausführen.

Wenn Sie einen neuen Zweig erstellen möchten   Behalte die Commits, die du erstellst, kannst du tun   so (jetzt oder später) mit -b mit dem   Checkout-Befehl erneut. Beispiel:

git checkout -b neuer_branch_name

Nun, um sie auf den Meister zu bringen:

Tu einen git reflog oder einfach nur git log und notiere deine Commits. Jetzt git checkout master und git merge die commits.

git merge HEAD@{1}

Bearbeiten:

Um hinzuzufügen, verwenden Sie git rebase -i nicht nur zum Löschen / Löschen von Commits, die Sie nicht benötigen, sondern auch um sie zu bearbeiten. Erwähnen Sie einfach "edit" in der Commit-Liste und Sie werden in der Lage sein, Ihr Commit zu ändern und dann ein git rebase --continue voran gehen. Dies hätte sichergestellt, dass du niemals zu einem abgetrennten HEAD gekommen bist.


78
2018-04-24 18:41



Bringen Sie Ihr detachiertes Commit in eine eigene Verzweigung

Einfach laufen git checkout -b mynewbranch.

Dann renne git logund du wirst sehen, dass Commit jetzt ist HEAD auf dieser neuen Filiale.


29
2018-05-20 02:44



Wenn Sie nur den Zweig beherrschen und wieder "entwickeln" wollen oder ein Feature, dann machen Sie das einfach:

git checkout origin/develop

Hinweis: Auschecken Herkunft / Entwicklung.

Sie befinden sich in Abgetrennter Kopf Zustand. Sie können sich umsehen, experimentieren ändert und committiert sie, und Sie können alle Commits, die Sie dabei machen, verwerfen Zustand, ohne irgendwelche Zweige zu beeinflussen, indem Sie eine andere Kasse ausführen ...

dann

git checkout -b develop

Es klappt :)


18
2017-11-08 13:24



Wenn Sie Ihren aktuellen abgetrennten HEAD drücken möchten (überprüfen Sie git log vor), versuche:

git push origin HEAD:master

um deinen abgetrennten HEAD im Ursprungszweig in den Masterzweig zu senden. Wenn dein Push abgelehnt wird, versuche es git pull origin master zuerst, um die Änderungen vom Ursprung zu erhalten. Wenn Sie sich nicht um die Änderungen aus dem Ursprung kümmern und diese abgelehnt werden, weil Sie eine absichtliche Rebase durchgeführt haben und Sie den Ursprung / Master durch Ihren derzeit getrennten Zweig ersetzen möchten, dann können Sie dies erzwingen (-f). Falls Sie Zugriff auf frühere Commits verloren haben, können Sie immer laufen git reflog um die Geschichte von allen Zweigen zu sehen.


Versuchen Sie die folgenden Befehle, um einen Master-Zweig wiederherzustellen, während Sie die Änderungen beibehalten:

git rebase HEAD master
git checkout master

Sehen: Git: "Derzeit auf keinem Zweig." Gibt es einen einfachen Weg, um in einen Zweig zurückzukehren, während die Änderungen beibehalten werden?


16
2017-09-17 20:35



Wenn du dir absolut sicher bist, dass HEAD der gute Zustand ist:

git branch -f master HEAD
git checkout master

Sie können wahrscheinlich nicht zum Ursprung stoßen, da Ihr Meister vom Ursprung abweicht. Wenn Sie sicher sind, dass niemand anderes das Repo verwendet, können Sie Folgendes erzwingen:

git push -f

Am nützlichsten, wenn Sie sich in einem Feature-Zweig befinden, den niemand sonst verwendet.


7
2018-03-01 09:31



Folgendes funktionierte für mich (mit nur Branch Master):

git push origin HEAD:master
git checkout master        
git pull

Der erste drückt den abgekoppelten HEAD auf den entfernten Ursprung.

Der zweite wechselt zum Zweigmeister.

Der dritte stellt den HEAD wieder her, der an den Zweig-Master angehängt wird.

Wenn der Push abgelehnt wird, können Probleme beim ersten Befehl auftreten. Aber das wäre nicht länger ein Problem von distanziertem Kopf, sondern es ist die Tatsache, dass der distanzierte HEAD einige entfernte Änderungen nicht bemerkt.


7
2018-01-07 12:13



Alles, was Sie tun müssen, ist 'git checkout [branch-name]', wobei [branch-name] der Name des ursprünglichen Zweiges ist, von dem Sie in einen losgelösten Kopfstatus gelangt sind. Das (von asdfasdf losgelöste) wird verschwinden.

So, zum Beispiel, im Zweig 'dev' checkst du das Commit asdfasd14314 ->

'git checkout asdfasd14314'

Sie sind jetzt in einem losgelösten Kopfzustand

'Git Branch' wird etwas wie -> auflisten

* (detached from asdfasdf)
  dev
  prod
  stage

aber um aus dem losgelösten Kopfzustand zu kommen und zurück zu dev ->

'git checkout dev'

und dann 'git branch' wird Liste ->

* dev
  prod
  stage

aber das ist natürlich, wenn du nicht vorhast, irgendwelche Veränderungen aus dem losgelösten Kopfzustand zu halten, aber ich merke, dass ich das viel mache, nicht vorhabe, irgendwelche Änderungen vorzunehmen, sondern nur ein vorheriges Commit zu betrachten


4
2017-10-17 19:49