Bewegen Sie den Verzweigungszeiger ohne Auschecken auf ein anderes Commit

760

Um den Verzweigungszeiger eines ausgecheckten Zweigs zu verschieben, kann der git reset --hardBefehl verwendet werden. Aber wie verschiebt man den Verzweigungszeiger eines nicht ausgecheckten Zweigs, um auf ein anderes Commit zu zeigen (wobei alle anderen Dinge wie der verfolgte Remote-Zweig beibehalten werden)?

Mot
quelle
11
Klingt so, als wollten Sie nur einen Zweig aus einem anderen Commit als dem, aus dem er jetzt erstellt wurde. Wenn mein Verständnis korrekt ist, warum erstellen Sie dann nicht einfach einen neuen Zweig aus dem Commit, den Sie erstellen möchten, indem Sie git branch <branch-name> <SHA-1-of-the-commit>den alten Zweig verwenden und sichern?
Yasouser
6
@yasouser - Ich bin nicht sicher, welcher Dumping "Master" -Zweig eine gute Idee ist.
Bulwersator

Antworten:

578

Sie können dies für beliebige Refs tun. So verschieben Sie einen Verzweigungszeiger:

git update-ref -m "reset: Reset <branch> to <new commit>" refs/heads/<branch> <commit>

Die allgemeine Form:

git update-ref -m "reset: Reset <branch> to <new commit>" <ref> <commit>

Sie können Nissen über die Reflog-Nachricht auswählen, wenn Sie möchten - ich glaube, die branch -funterscheidet sich von der reset --hardeinen, und dies ist nicht genau eine davon.

Adam A.
quelle
39
Wo ist die Nachricht gut? Wo ist es gespeichert und wie kann man es später lesen?
Mot
4
HINWEIS: Dies funktioniert nicht bei nackten Repositorys. In nackten Repositorys müssen Sie 'git branch -f master <commit>' verwenden, um den Zweig zu aktualisieren (siehe die Antwort unten).
Juni Rhodos
37
Wenn Sie wie ich versehentlich <branch> anstelle von refs / Heads / <branch> verwenden, erhalten Sie eine neue Datei in Ihrem .git-Verzeichnis unter .git / <branch> und erhalten Nachrichten wie "refname 'master' ist mehrdeutig", wenn Sie versuchen, damit zu arbeiten. Sie können die zu löschende Datei aus Ihrem .git-Verzeichnis löschen.
David Minor
34
Es wurde nicht zur Zufriedenheit erklärt, warum dies besser ist als git branch -f. Um genau zu sein, scheint diese Methode zu sein: (A) schwerer zu verwenden (B) schwerer zu merken und (C) gefährlicher
Steven Lu
10
"Was genau ist mit willkürlichen Refs gemeint?" - Zweige sind nicht die einzige Art von Refs, die auf ein Commit verweisen. Es gibt Tags, und Sie können auch beliebige Refs / whatevs / myref-Refs selbst erstellen, die weder Zweige noch Tags sind. Ich glaube, das beantwortet auch Steven Lus Frage, was dies "besser" sein könnte. Ich bin damit einverstanden, dass branch -f am einfachsten ist, wenn Sie mit Zweigen arbeiten.
Adam A
964
git branch -f <branch-name> <new-tip-commit>
Chris Johnsen
quelle
24
Oder für willkürliche Verweise , git update-ref -m "reset: Reset <branch> to <new commit>" <branch> <commit>. (Sie können Nissen über die Reflog-Nachricht auswählen, wenn Sie möchten - ich glaube, die branch -feine unterscheidet sich von der reset --hardeinen, und dies ist nicht genau eine von beiden.)
Cascabel
4
Jefromi, bitte schreibe eine separate Antwort, damit du Stimmen bekommen kannst. :)
Mot
16
Dies ist eine bessere Antwort, da es den 99% -Fall behandelt und tatsächlich der Dokumentation entspricht. git help branchsagt "-f, --force Reset <branchname> auf <startpoint>, wenn <branchname> bereits existiert. Ohne -f weigert sich der Zweig git, einen vorhandenen Zweig zu ändern."
AlexChaffee
12
Ich mache git branch -f master <hash>und es sagt mir fatal: Cannot force update the current branch.Ummmm, ich muss was jetzt tun, einen anderen zufälligen Zweig überprüfen, bevor ich diesen Befehl verwenden darf?
Qwertie
20
Dies funktioniert nicht, wenn der Zweig, den Sie verschieben möchten, Ihr aktueller Zweig ist ( HEADzeigt darauf).
Vladimir Panteleev
135

Sie können auch git reset --hardeine Festschreibungsreferenz übergeben.

Zum Beispiel:

git checkout branch-name
git reset --hard new-tip-commit

Ich finde, dass ich so etwas nur selten mache:

Angenommen, diese Geschichte

$ git log --decorate --oneline --graph
* 3daed46 (HEAD, master) New thing I shouldn't have committed to master
* a0d9687 This is the commit that I actually want to be master

# Backup my latest commit to a wip branch
$ git branch wip_doing_stuff

# Ditch that commit on this branch
$ git reset --hard HEAD^

# Now my changes are in a new branch
$ git log --decorate --oneline --graph
* 3daed46 (wip_doing_stuff) New thing I shouldn't have committed to master
* a0d9687 (HEAD, master) This is the commit that I actually want to be master
Amiel Martin
quelle
Dies ist insofern am sinnvollsten, als man normalerweise HEAD oder HEAD ^ verwendet, um die Verzweigungsspitze in der Zeit zurück zu bewegen. Dies ist also konsistent, um das bevorstehende Commit anzugeben.
Justingordon
11
Dies ist in Ordnung, wenn Ihr Arbeitsbaum sauber ist. Wenn Sie viele bereitgestellte oder nicht bereitgestellte Änderungen haben, ist es wahrscheinlich besser, die git update-refoben beschriebenen Schritte auszuführen .
Ein bezahlter Nerd
16
Haben Sie bemerkt, dass Ihre „Antwort“ nichts hinzufügt, was nicht bereits Teil der Frage ist? - OP sagte: Wenn es ausgecheckt ist ... können Sie verwenden, git reset --hard ...dass Sie es hier nicht wiederholen müssen! :-(
Robert Siemer
6
@ Robert: Ich bin anderer Meinung. Die Frage sagte nicht, wie man es benutzt und das tut es. Es war schön, nicht danach suchen zu müssen.
Wilson F
7
@ WilsonF, vielleicht war es schön für dich, das hier zu finden, aber es beantwortet die Frage überhaupt nicht. Vielleicht ist es die Antwort auf eine andere Frage, aber hier ist es falsch .
Robert Siemer
52

Um die Diskussion zu bereichern und den myBranchZweig auf Ihr aktuelles Commit zu verschieben, lassen Sie einfach das zweite Argument nach-f

Beispiel:

git branch -f myBranch


Ich mache das normalerweise, wenn ich mich rebasein einem Zustand mit losgelöstem KOPF befinde :)

Matheus Felipe
quelle
13

In gitk --all:

  • Klicken Sie mit der rechten Maustaste auf das gewünschte Commit
  • -> neuen Zweig erstellen
  • Geben Sie den Namen eines vorhandenen Zweigs ein
  • Drücken Sie die Eingabetaste in dem Dialogfeld, in dem bestätigt wird, dass der alte Zweig dieses Namens ersetzt wurde .

Beachten Sie, dass beim erneuten Erstellen statt Ändern des vorhandenen Zweigs Informationen zum Tracking-Zweig verloren gehen . (Dies ist im Allgemeinen kein Problem für einfache Anwendungsfälle, in denen es nur eine Fernbedienung gibt und Ihre lokale Niederlassung denselben Namen wie die entsprechende Niederlassung in der Fernbedienung hat. Weitere Informationen finden Sie in den Kommentaren. Vielen Dank an @mbdevpl, dass Sie auf diesen Nachteil hingewiesen haben.)

Es wäre cool, wenn gitkes eine Funktion gäbe, bei der das Dialogfeld drei Optionen hätte: Überschreiben, Vorhandene ändern oder Abbrechen.


Selbst wenn Sie normalerweise ein Kommandozeilen-Junkie wie ich sind git guiund gitksehr gut für die Teilmenge der Git-Nutzung ausgelegt sind, die sie zulassen. Ich empfehle dringend, sie für das zu verwenden, was sie können (dh selektiv Staging von Hunks in / aus dem Index in Git-GUI und auch nur Festschreiben) (Strg-s, um eine Abmeldung hinzuzufügen: Zeile, Strg-Eingabe zum Festschreiben .)

gitk ist ideal, um ein paar Zweige im Auge zu behalten, während Sie Ihre Änderungen in eine nette Patch-Serie sortieren, um sie im Upstream einzureichen, oder alles andere, wo Sie mit mehreren Zweigen den Überblick behalten müssen, in dem Sie sich gerade befinden.

Ich habe noch nicht einmal einen grafischen Dateibrowser geöffnet, aber ich liebe gitk / git gui.

Peter Cordes
quelle
1
So einfach! Ich habe vielleicht gerade von Gitg zu Gitk konvertiert.
Michael Cole
Auf diese Weise gehen jedoch die Verfolgungszweiginformationen verloren.
mbdevpl
@mbdevpl: Ich bin nicht wirklich ein Git-Experte. Ich glaube ich verstehe was du meinst, aber nicht die Implikationen. Ich habe dies ziemlich oft verwendet und war immer noch in der Lage, diese Zweige auf einer Fernbedienung zu gleichnamigen Zweigen zu verschieben. Was bewirkt die Zuordnung zwischen einem Zweig und seinem Remote-Tracking-Zweig für Sie?
Peter Cordes
1
@PeterCordes Ineed, wenn Zweignamen nicht übereinstimmen, ist es wichtig. Auch wenn es mehr als eine Fernbedienung gibt. Wenn Sie die Git-Eingabeaufforderung verwenden, um den Zweigstatus anzuzeigen, wird die Festschreibungsentfernung zu Ihrem Tracking-Zweig angezeigt (falls festgelegt). Auch die git statusAusgabe ist betroffen. Zusätzlich kann in einigen Fällen git fetchund git pushwird nicht funktionieren remote explizit ohne Angabe , wenn Sie nicht den Tracking - Zweig gesetzt haben. Ich weiß nicht über alle Fälle Bescheid, aber für mich lautet die allgemeine Faustregel, dass es aus Gründen der Bequemlichkeit und Schnelligkeit der Arbeit besser ist, die Nachverfolgungszweige in der richtigen Reihenfolge zu haben.
mbdevpl
7

Die empfohlene Lösunggit branch -f branch-pointer-to-move new-pointer in TortoiseGit :

  • "Git Show log"
  • Aktivieren Sie "Alle Zweige".
  • In der Zeile, zu der der Verzweigungszeiger verschoben werden soll (neuer Zeiger):
    • Klicken Sie mit der rechten Maustaste auf "Zweig in dieser Version erstellen".
    • Geben Sie neben "Zweig" den Namen des zu verschiebenden Zweigs ein (Zweigzeiger zum Verschieben).
    • Überprüfen Sie unter "Base On", ob der neue Zeiger korrekt ist
    • Aktivieren Sie "Force"
    • OK

Geben Sie hier die Bildbeschreibung ein

Geben Sie hier die Bildbeschreibung ein

Axt.
quelle
4

Ehrlich gesagt bin ich überrascht, wie niemand über den git pushBefehl nachgedacht hat :

git push -f . <destination>:<branch>

Der Punkt (.) Verweist auf das lokale Repository, und Sie benötigen möglicherweise die Option -f, da sich das Ziel möglicherweise "hinter seinem Remote-Gegenstück" befindet .

Obwohl dieser Befehl zum Speichern Ihrer Änderungen auf Ihrem Server verwendet wird, ist das Ergebnis genau das gleiche, als würde der Remote-Zweig ( <branch>) auf denselben Commit wie der lokale Zweig ( <destination>) verschoben.

Adrian
quelle
Sie können dies auch tun, ohne -flokale Probleme zu vermeiden. Zum Beispiel git fetch origin && git push . origin/develop:developist eine Fail-Fast-Version vongit checkout develop && git pull --ff-only
btown
1

Öffnen Sie die Datei .git/refs/heads/<your_branch_name>und ändern Sie den dort gespeicherten Hash in den, in den Sie den Kopf Ihres Zweigs verschieben möchten. Bearbeiten und speichern Sie die Datei einfach mit einem beliebigen Texteditor. Stellen Sie einfach sicher, dass der zu ändernde Zweig nicht der aktuell aktive ist.

Haftungsausschluss: Wahrscheinlich kein ratsamer Weg, dies zu tun, aber die Arbeit erledigt.

Guillermo Gutiérrez
quelle
1
Ich bin mir nicht sicher, ob dies der chaotische oder böse Weg ist. 🤔 😉
Keith Russell
@KeithRussell kann beides sein: P
Guillermo Gutiérrez
0

Wenn das Commit, auf das Sie zeigen möchten, vor dem aktuellen Zweig liegt (was der Fall sein sollte, es sei denn, Sie möchten die letzten Commits des aktuellen Zweigs rückgängig machen), können Sie einfach Folgendes tun:

git merge <commit>
Jean Paul
quelle
Frage gefragt, was zu tun ist, wenn der Zweig nicht ausgecheckt ist.
Keith Russell
Hoppla, ich habe diesen Punkt verpasst. In diesem Fall können Sie das tun, git push . <commit>:<branch>was bereits vorgeschlagen wurde.
Jean Paul