Lassen Sie uns zunächst klären, was HEAD ist und was es bedeutet, wenn es abgenommen wird.
HEAD ist der symbolische Name für das aktuell ausgecheckte Commit. Wenn HEAD nicht getrennt ist (die „normale“ Situation 1 : Sie haben einen Zweig ausgecheckt), zeigt HEAD tatsächlich auf den „ref“ eines Zweigs und der Zweig zeigt auf das Commit. HEAD ist somit an einen Zweig „gebunden“. Wenn Sie ein neues Commit durchführen, wird der Zweig, auf den HEAD zeigt, aktualisiert, um auf das neue Commit zu verweisen. HEAD folgt automatisch, da es nur auf den Zweig zeigt.
git symbolic-ref HEAD
Ausbeuten refs/heads/master
Der Zweig mit dem Namen "master" wird ausgecheckt.
git rev-parse refs/heads/master
Yield 17a02998078923f2d62811326d130de991d1a95a
Dieses Commit ist der aktuelle Tipp oder „Kopf“ des Hauptzweigs.
git rev-parse HEAD
ergibt auch 17a02998078923f2d62811326d130de991d1a95a
Dies ist, was es bedeutet, ein "symbolischer Verweis" zu sein. Es zeigt durch eine andere Referenz auf ein Objekt.
(Symbolische Verweise wurden ursprünglich als symbolische Links implementiert, später jedoch in einfache Dateien mit zusätzlicher Interpretation geändert, damit sie auf Plattformen ohne Symlinks verwendet werden können.)
Wir haben HEAD
→ refs/heads/master
→17a02998078923f2d62811326d130de991d1a95a
Wenn HEAD getrennt ist, zeigt es direkt auf ein Commit - anstatt indirekt über einen Zweig auf eines zu verweisen. Sie können sich einen abgetrennten KOPF als einen unbenannten Zweig vorstellen.
git symbolic-ref HEAD
scheitert mit fatal: ref HEAD is not a symbolic ref
git rev-parse HEAD
Renditen 17a02998078923f2d62811326d130de991d1a95a
Da es sich nicht um einen symbolischen Verweis handelt, muss er direkt auf das Commit selbst verweisen.
Wir haben HEAD
→17a02998078923f2d62811326d130de991d1a95a
Das Wichtigste, an das Sie sich bei einem abgetrennten HEAD erinnern sollten, ist, dass wenn das Commit, auf das es zeigt, ansonsten nicht referenziert ist (kein anderer Ref kann es erreichen), es beim Auschecken eines anderen Commits „baumelt“. Letztendlich werden solche baumelnden Commits durch den Garbage Collection-Prozess zurückgeschnitten (standardmäßig werden sie mindestens 2 Wochen lang aufbewahrt und können länger aufbewahrt werden, indem auf HEADs Reflog verwiesen wird).
1
Es ist vollkommen in Ordnung, „normale“ Arbeiten mit einem abgetrennten KOPF auszuführen. Sie müssen nur nachverfolgen, was Sie tun, um zu vermeiden, dass Sie die abgelaufene Geschichte aus dem Reflog heraus fischen müssen.
Die Zwischenschritte einer interaktiven Rebase werden mit einem abgetrennten HEAD ausgeführt (teilweise, um eine Verschmutzung des Reflogs des aktiven Zweigs zu vermeiden). Wenn Sie den vollständigen Rebase-Vorgang abgeschlossen haben, wird Ihr ursprünglicher Zweig mit dem kumulativen Ergebnis des Rebase-Vorgangs aktualisiert und HEAD erneut an den ursprünglichen Zweig angehängt. Ich vermute, dass Sie den Rebase-Prozess nie vollständig abgeschlossen haben. Dadurch erhalten Sie einen getrennten HEAD, der auf das Commit verweist, das zuletzt von der Rebase-Operation verarbeitet wurde.
Um sich von Ihrer Situation zu erholen, sollten Sie einen Zweig erstellen, der auf das Commit verweist, auf das Ihr losgelöster HEAD derzeit zeigt:
git branch temp
git checkout temp
(Diese beiden Befehle können als abgekürzt werden. git checkout -b temp
)
Dadurch wird Ihr HEAD wieder mit dem neuen temp
Zweig verbunden.
Als Nächstes sollten Sie das aktuelle Commit (und seinen Verlauf) mit dem normalen Zweig vergleichen, an dem Sie voraussichtlich arbeiten werden:
git log --graph --decorate --pretty=oneline --abbrev-commit master origin/master temp
git diff master temp
git diff origin/master temp
(Sie möchten wahrscheinlich mit den Protokolloptionen experimentieren: Hinzufügen -p
, weglassen --pretty=…
, um die gesamte Protokollnachricht anzuzeigen usw.)
Wenn Ihr neuer temp
Zweig gut aussieht, möchten Sie ihn möglicherweise aktualisieren (z. B.), master
um darauf zu verweisen:
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 den temporären Zweig löschen:
git branch -d temp
Schließlich möchten Sie wahrscheinlich die wiederhergestellte Geschichte vorantreiben:
git push origin master
Möglicherweise müssen Sie --force
am Ende dieses Befehls einen Push hinzufügen , wenn der Remote-Zweig nicht schnell zum neuen Commit weitergeleitet werden kann (dh Sie haben ein vorhandenes Commit gelöscht oder neu geschrieben oder auf andere Weise einen Teil des Verlaufs neu geschrieben).
Wenn Sie sich mitten in einer Rebase-Operation befanden, sollten Sie diese wahrscheinlich bereinigen. Sie können überprüfen, ob eine Rebase ausgeführt wurde, 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 zu einem zusätzlichen Zurücksetzen, das Sie wahrscheinlich vermeiden möchten (es verschiebt HEAD zurück zum ursprünglichen Zweig und setzt es zurück zum ursprünglichen Commit, wodurch einige der oben geleisteten Arbeiten rückgängig gemacht werden).