Wie kann ich HEAD an einen früheren Ort zurückversetzen? (Abgenommener Kopf) & Commits rückgängig machen

178

In Git habe ich versucht, dies zu tun, squash commitindem ich in einem anderen Zweig zusammengeführt und dann zurückgesetzt habeHEAD auf den vorherigen Ort zurückgesetzt habe:

git reset origin/master

Aber ich muss da raus. Wie kann ich HEAD zurück zum vorherigen Speicherort verschieben?

Ich habe das SHA-1-Fragment ( 23b6772) des Commits, in das ich es verschieben muss. Wie kann ich zu diesem Commit zurückkehren?

Timpone
quelle
11
HEAD ist nur ein Zeiger auf Ihren aktuellen Standort (oder genauer gesagt auf die Überarbeitung). git checkout 23b6772sollte tun.
Jaroslaw Admin
Mögliches Duplikat von Revert Git Repo zu einem früheren Commit
Andrew C
1
@ JaroslawAdmin Nein, sollte es nicht . Das direkte Auschecken eines Commits ist der Grund, warum der getrennte HEAD-Status aufgetreten ist (da Remote-Tracking-Zweige nicht selbst ausgecheckt werden können und automatisch auf das Commit zurückgreifen, auf das sie verweisen, wenn Sie dies wie OP versuchen). Entschuldigen Sie auch die Nekromantik Kommentar :-) Ich hoffe irgendwie, dass das anfängliche Problem bereits gelöst ist ...
RomainValeri

Antworten:

392

Bevor wir antworten, fügen wir einige Hintergrundinformationen hinzu und erklären, was dies HEADist.

First of all what is HEAD?

HEADist einfach ein Verweis auf das aktuelle Commit (aktuell) in der aktuellen Verzweigung.
Es kann immer nur eine einzige HEADgeben (ausgenommen git worktree).

Der Inhalt von HEADwird darin gespeichert .git/HEADund enthält die 40 Bytes SHA-1 des aktuellen Commits.


detached HEAD

Wenn Sie sich nicht im letzten Commit befinden, bedeutet dies, dass HEADauf ein vorheriges Commit im Verlauf verwiesen wird detached HEAD.

Geben Sie hier die Bildbeschreibung ein

In der Befehlszeile sieht es folgendermaßen aus: SHA-1 anstelle des Zweignamens, da der HEADnicht auf die Spitze des aktuellen Zweigs zeigt:

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein


Einige Optionen zur Wiederherstellung nach einem abgetrennten KOPF:


git checkout

git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back

Dadurch wird ein neuer Zweig ausgecheckt, der auf das gewünschte Commit verweist.
Dieser Befehl checkt zu einem bestimmten Commit aus.
An diesem Punkt können Sie einen Zweig erstellen und ab diesem Zeitpunkt mit der Arbeit beginnen.

# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>

# Create a new branch forked to the given commit
git checkout -b <branch name>

git reflog

Sie können das auch immer verwenden reflog.
git reflog zeigt jede Änderung an, die das aktualisiert hat, HEADund das Auschecken des gewünschten Reflog-Eintrags setzt das Zurücksetzen HEADauf dieses Commit.

Jedes Mal, wenn der KOPF geändert wird, wird ein neuer Eintrag in der reflog

git reflog
git checkout HEAD@{...}

Dadurch kehren Sie zu Ihrem gewünschten Commit zurück

Geben Sie hier die Bildbeschreibung ein


git reset --hard <commit_id>

"Bewegen" Sie Ihren HEAD zurück zum gewünschten Commit.

# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32

# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
  • Hinweis: ( Seit Git 2.7 ) können Sie auch das verwenden git rebase --no-autostash.

git revert <sha-1>

"Rückgängig machen" des angegebenen Commits oder Commit-Bereichs.
Der Befehl zum Zurücksetzen "macht" alle Änderungen rückgängig, die am angegebenen Commit vorgenommen wurden.
Ein neues Commit mit dem Undo-Patch wird festgeschrieben, während das ursprüngliche Commit ebenfalls im Verlauf verbleibt.

# Add a new commit with the undo of the original one.
# The <sha-1> can be any commit(s) or commit range
git revert <sha-1>

Dieses Schema zeigt, welcher Befehl was tut.
Wie Sie dort sehen können, reset && checkoutändern Sie die HEAD.

Geben Sie hier die Bildbeschreibung ein

CodeWizard
quelle
Wenn Sie sich nicht im letzten Commit befinden - was bedeutet, dass HEAD auf ein vorheriges Commit im Verlauf verweist, wird es als getrennter HEAD bezeichnet, es sei denn, dieses vorherige Commit im Verlauf ist die Spitze eines anderen Zweigs. Nach meiner Erfahrung können Sie sagen, dass Sie getrennt sind, wenn HEAD nicht auf ein Commit verweist, auf das auch ein Zweig verweist. Dies gilt nicht für Tags.
Tim
Sie können sich in einem getrennten HEAD befinden und gleichzeitig einen Zweig mit demselben Commit wie der HEAD dieses Zweigs haben. Ich verstehe Ihren Kommentar nicht
CodeWizard
3
Ich habe Probleme mit Ihrer Verwendung von Inline-Code-Markup für Überschriften :)
jub0bs
Könnte keinen besseren Weg finden, es zu betonen. Fühlen Sie sich frei zu bearbeiten. Sie sind mehr als willkommen
CodeWizard
22

Machen

git reset 23b6772

Um zu sehen, ob Sie an der richtigen Position sind:

git status

Du wirst etwas sehen

Auf Zweigstellenstamm Ihre Zweigstelle befindet sich um 17 Commits hinter 'origin / master' und kann schnell vorgespult werden.

Schreiben Sie dann den Verlauf auf Ihrer Fernbedienung neu, um die Änderung widerzuspiegeln:

git push --force-with-lease // a useful command @oktober mentions in comments
eigenartig
quelle
1
Seien Sie äußerst vorsichtig mit git push --force. In vielen Situationen werden Sie für eine Weile die am wenigsten beliebte Person im Team sein ...
Kay V
Um den obigen Hinweis zu ergänzen, bin ich gerade auf dieses Zitat unter about.gitlab.com/blog/2014/11/26/keeping-your-code-protected gestoßen und musste es hinzufügen: "Ein einzelner git push --force-Befehl kann den Tag für viele Leute leicht ruinieren: [186 Jenkins] Repositories haben ihre Zweigstellen zurückgespult, um auf ältere Commits zu verweisen, und tatsächlich wurden die neueren Commits nach dem schlechten Git-Push verlegt. " - sehr unbeliebter Entwickler ....
Kay V
2
@ KayV werfen Sie einen Blick auf git push --force-with-lease(Thoughtbot-Artikel : oughtbot.com/blog/git-push-force-with-lease )
Oktober
1
Nützliche Flagge, @oktober und ein guter Artikel. Danke, dass du es hier hinzugefügt und mich darüber angerufen hast.
Kay V
1
Danke! Dies hat mir geholfen, eine schlechte Zusammenführung aufzuheben. Da Zusammenschlüsse nicht so reagieren revertwie Commits, befand ich mich in einer unglaublich schwierigen Situation. force-with-leasegab mir das Vertrauen, die Git-Geschichte der Branche neu zu schreiben, ohne die Arbeit anderer zu beeinträchtigen. Bravo!
anon58192932
11

Schnellstmögliche Lösung (nur 1 Schritt)

Verwenden git checkout -

Du wirst sehen Switched to branch <branch_name>. Bestätigen Sie, dass es sich um den gewünschten Zweig handelt.


Kurze Erklärung: Mit diesem Befehl wird HEAD wieder in die letzte Position gebracht. Siehe Hinweis zu den Ergebnissen am Ende dieser Antwort.


Mnemonik: Dieser Ansatz ähnelt der Verwendung cd -, um zu Ihrem zuvor besuchten Verzeichnis zurückzukehren. Die Syntax und die zutreffenden Fälle stimmen ziemlich gut überein (z. B. ist es nützlich, wenn HEAD tatsächlich dorthin zurückkehren soll, wo es war).


Methodischere Lösung (2 Schritte, aber einprägsam)

Der schnelle Ansatz löst die Frage des OP. Aber was ist, wenn Ihre Situation etwas anders ist: Angenommen, Sie haben Bash neu gestartet und sich dann mit getrenntem KOPF wiedergefunden. In diesem Fall sind hier zwei einfache, leicht zu merkende Schritte.

1. Wählen Sie den gewünschten Zweig aus

Verwenden git branch -v

Sie sehen eine Liste der vorhandenen lokalen Niederlassungen. Suchen Sie sich den Filialnamen, der Ihren Anforderungen entspricht.

2. Bewegen Sie den KOPF dorthin

Verwenden git checkout <branch_name>

Du wirst sehen Switched to branch <branch_name>. Erfolg!


Ergebnisse

Mit beiden Methoden können Sie jetzt wie zuvor mit dem Hinzufügen und Festschreiben Ihrer Arbeit fortfahren: Ihre nächsten Änderungen werden nachverfolgt <branch_name>.

Beachten Sie, dass beide git checkout -und git checkout <branch_name>zusätzliche Anweisungen geben, wenn Sie Änderungen festgeschrieben haben, während HEAD getrennt wurde.

Kay V.
quelle
Das funktioniert nicht , weil , wenn ich (unter der Annahme , dass 8acc968 ist HEAD ~ 2) git checkout 8acc968dann git branch -vhat MyBranchin der Liste unten ... aber dann git checkout MyBranchlöscht meine Kommentare.
eigenartig
Hi @amuliar - git checkout 8acc968prüft ein Commit, keinen Zweig. Wenn MyBranchSie die gewünschten Commits haben, versuchen Sie es git checkout MyBranch. Wenn die Änderungen in Commit 8acc968 nicht enthalten sind, müssen Sie diese Änderungen nach dem Auschecken des Zweigs zusammenführen.
Kay V
Danke für die Antwort! Ich habe git checkoutein vorheriges Commit gesehen und wollte zum letzten Commit zurückkehren. Aber ohne den letzten Commit-Hash war ich ziemlich verloren. Diese Lösung ist perfekt für meine Situation!
Zyy
4

Die Frage kann gelesen werden als:

Ich war in losgelöstem Zustand mit HEADat 23b6772und tippte git reset origin/master(weil ich quetschen wollte). Jetzt habe ich meine Meinung geändert, wie gehe ich zurück HEADzu sein 23b6772?

Die einfache Antwort lautet: git reset 23b6772

Aber ich bin auf diese Frage HEADgestoßen, weil ich es satt hatte, jedes Mal , wenn ich auf das vorherige verweisen wollte, Commit-Hashes oder deren Abkürzung zu tippen (kopieren und einfügen) und googelte, um zu sehen, ob es irgendeine Art von Kurzschrift gab.

Es stellt sich heraus, dass es gibt!

git reset -(oder in meinem Fall git cherry-pick -)

Was übrigens dasselbe war cd -, um zum vorherigen aktuellen Verzeichnis in * nix zurückzukehren! Also Hurra, ich habe zwei Dinge mit einer Klappe gelernt.

Antak
quelle
0

Wenn Sie den Befehl ausführen, git checkout commit_idist HEAD getrennt von 13ca5593d(say commit-id)und Branch ist länger verfügbar.

Zum vorherigen Speicherort zurückkehren Führen Sie den Befehl schrittweise aus -

  1. git pull origin branch_name (sag Meister)
  2. git checkout branch_name
  3. git pull origin branch_name

Sie kehren mit einem aktualisierten Commit aus dem Remote-Repository zum vorherigen Speicherort zurück.

Deepak Kumar
quelle
0

Heute habe ich fälschlicherweise ein Commit ausgecheckt und angefangen, daran zu arbeiten, wobei ich einige Commits für einen getrennten HEAD-Status vorgenommen habe. Dann habe ich mit dem folgenden Befehl zum Remote-Zweig gewechselt:

git push origin HEAD: <My-remote-branch>

Dann

git checkout <My-remote-branch>

Dann

git pull

Ich habe endlich alle Änderungen in meinem Zweig erhalten, die ich in losem KOPF vorgenommen habe.

Zaid Mirza
quelle
0

Dies ist möglicherweise keine technische Lösung, funktioniert aber. (wenn einer Ihrer Teamkollegen dieselbe Niederlassung vor Ort hat)

Nehmen wir an, Ihr Filialname lautet branch-xxx .

Schritte zum Lösen:

  • Nicht aktualisieren oder ziehen - nichts
  • Erstellen Sie einfach einen neuen Zweig ( branch-yyy ) aus branch-xxx auf seinem Computer
  • Das ist alles, alle Ihre vorhandenen Änderungen werden in diesem neuen Zweig ( Zweig-JJJ ) sein. Mit diesem Zweig können Sie Ihre Arbeit fortsetzen.

Hinweis: Auch dies ist keine technische Lösung, aber sie wird auf jeden Fall helfen.

Sathish Kumar
quelle