Normalerweise reiche ich eine Liste von Commits zur Überprüfung ein. Wenn ich folgende Commits habe:
HEAD
Commit3
Commit2
Commit1
... Ich weiß, dass ich Head Commit mit ändern kann git commit --amend
. Aber wie kann ich Änderungen vornehmen Commit1
, da es sich nicht um das HEAD
Commit handelt?
git
git-rewrite-history
Sam Liao
quelle
quelle
Antworten:
Sie können Git Rebase verwenden . Wenn Sie beispielsweise das Commit ändern möchten
bbc643cd
, führen Sie es ausBitte beachten Sie das Caret
^
am Ende des Befehls, da Sie tatsächlich auf das Commit zurückgreifen müssen , bevor Sie es ändern möchten .Im Standard - Editor, ändern ,
pick
umedit
in der Linie zu erwähnen ‚bbc643cd‘.Speichern Sie die Datei und beenden Sie: git interpretiert die Befehle in der Datei und führt sie automatisch aus. Sie befinden sich in der vorherigen Situation, in der Sie gerade ein Commit erstellt haben
bbc643cd
.An diesem Punkt
bbc643cd
ist Ihr letztes Commit und Sie können es leicht ändern : Nehmen Sie Ihre Änderungen vor und schreiben Sie sie dann mit dem Befehl fest:Geben Sie danach Folgendes ein:
um zum vorherigen HEAD-Commit zurückzukehren.
WARNUNG : Beachten Sie, dass dies den SHA-1 dieses Commits sowie alle untergeordneten Elemente ändert. Mit anderen Worten, dies schreibt den Verlauf von diesem Punkt an neu. Sie können Repos dabei unterbrechen, wenn Sie mit dem Befehl drücken
git push --force
quelle
reword
Aktion ingit rebase -i
anstelle von verwendenedit
(sie öffnet automatisch den Editor und fährt mit den restlichen Rebase-Schritten fort; dies vermeidet die Verwendung vongit commit --ammend
undgit rebase --continue
wenn Sie nur die Commit-Nachricht und nicht den Inhalt ändern müssen ).git stash
vorhergit rebase
undgit stash pop
nachher ausführen müssen , wenn Änderungen anstehen.git commit --all --amend --no-edit
hier blind zu verwenden . Alles was ich danach tun musstegit rebase -i ...
war danngit commit --amend
normal zu seingit rebase --continue
.Verwenden Sie die fantastische interaktive Rebase:
Suchen Sie das gewünschte Commit, ändern Sie es
pick
ine
(edit
) und speichern und schließen Sie die Datei. Git wird zu diesem Commit zurückspulen, sodass Sie entweder:git commit --amend
, um Änderungen vorzunehmen, odergit reset @~
diese Option, um das letzte Commit zu verwerfen, jedoch nicht die Änderungen an den Dateien (dh, Sie gelangen zu dem Punkt, an dem Sie die Dateien bearbeitet, aber noch nicht festgeschrieben hatten).Letzteres ist nützlich, um komplexere Aufgaben wie das Aufteilen in mehrere Commits auszuführen.
Führen Sie dann aus
git rebase --continue
, und Git spielt die nachfolgenden Änderungen zusätzlich zu Ihrem geänderten Commit erneut ab. Möglicherweise werden Sie aufgefordert, einige Zusammenführungskonflikte zu beheben.Hinweis:
@
ist eine Abkürzung fürHEAD
und~
ist das Commit vor dem angegebenen Commit.Weitere Informationen zum Umschreiben des Verlaufs finden Sie in den Git-Dokumenten.
Hab keine Angst, dich zu erholen
ProTip ™: Haben Sie keine Angst, mit "gefährlichen" Befehlen zu experimentieren, die den Verlauf neu schreiben. * - Git löscht Ihre Commits standardmäßig 90 Tage lang nicht. Sie finden sie im Reflog:
* Achten Sie auf Optionen wie
--hard
und--force
obwohl - sie können Daten verwerfen.* Schreiben Sie den Verlauf auch nicht in Zweigen neu, in denen Sie zusammenarbeiten.
Auf vielen Systemen
git rebase -i
wird Vim standardmäßig geöffnet. Vim funktioniert nicht wie die meisten modernen Texteditoren. Sehen Sie sich also an, wie Sie mit Vim die Basis neu erstellen können . Wenn Sie lieber einen anderen Editor verwenden möchten, ändern Sie ihn mitgit config --global core.editor your-favorite-text-editor
.quelle
@
als Abkürzung für verwenden könnenHEAD
. Vielen Dank für die Veröffentlichung.git reset @~
genau das, was ich tun wollte, nachdem ich mich für Commit entschieden hattegit rebase ...
. Du bist mein Held)Interaktives Rebase mit
--autosquash
ist etwas, das ich häufig verwende, wenn ich frühere Commits tiefer im Verlauf korrigieren muss. Dies beschleunigt im Wesentlichen den Prozess, den die Antwort von ZelluX veranschaulicht, und ist besonders praktisch, wenn Sie mehr als ein Commit bearbeiten müssen.Aus der Dokumentation:
Angenommen, Sie haben eine Geschichte, die so aussieht:
und Sie haben Änderungen, die Sie an Commit2 ändern möchten, und übernehmen dann Ihre Änderungen mit
Alternativ können Sie das Commit-sha anstelle der Commit-Nachricht verwenden,
"fixup! e8adec4
oder sogar nur ein Präfix der Commit-Nachricht.Starten Sie dann zuvor eine interaktive Rebase für das Commit
Ihr Editor wird mit den bereits korrekt bestellten Commits geöffnet
Sie müssen lediglich speichern und beenden
quelle
git commit --fixup=@~
anstelle von verwendengit commit -m "fixup! Commit2"
. Dies ist besonders nützlich, wenn Ihre Commit-Nachrichten länger sind und es schwierig wäre, das Ganze abzutippen.Lauf:
$ git rebase --interactive commit_hash^
Jedes
^
gibt an, wie viele Commits Sie zurück bearbeiten möchten. Wenn es nur eines ist (der von Ihnen angegebene Commit-Hash), fügen Sie einfach einen hinzu^
.Mit Vim Sie die Wörter ändern ,
pick
umreword
für die Commits Sie ändern möchten, zu speichern und beenden (:wq
). Dann fordert git Sie bei jedem Commit auf, das Sie als Reword markiert haben, damit Sie die Commit-Nachricht ändern können.Jede Festschreibungsnachricht müssen Sie speichern und beenden (
:wq
), um zur nächsten Festschreibungsnachricht zu gelangenWenn Sie beenden möchten, ohne die Änderungen zu übernehmen, drücken Sie
:q!
BEARBEITEN : Um darin zu navigieren , gehen
vim
Siej
nach oben,k
nach unten,h
nach links undl
nach rechts (alles imNORMAL
Modus, drücken SieESC
, um in denNORMAL
Modus zu wechseln). Um einen Text zu bearbeiten, drückeni
Sie, um in denINSERT
Modus zu gelangen, in dem Sie Text einfügen. Drücken SieESC
, um zumNORMAL
Modus zurückzukehren :)UPDATE : Hier ist ein großartiger Link aus der Github-Liste. Wie man (fast) alles mit Git rückgängig macht
quelle
git push --force
?git push --force
überschreibt, ist das Überschreiben der Remote-Commits mit Ihren lokalen Commits. Das ist nicht der Fall bei diesem Thema :)Wenn Sie aus irgendeinem Grund keine interaktiven Editoren mögen, können Sie diese verwenden
git rebase --onto
.Angenommen, Sie möchten Änderungen vornehmen
Commit1
. Verzweigen Sie zuerst von vorCommit1
:Zweitens greifen
Commit1
mitcherry-pick
:Ändern Sie nun Ihre Änderungen und erstellen Sie
Commit1'
:Und schließlich, nachdem Sie alle anderen Änderungen gespeichert haben, übertragen Sie den Rest Ihrer Commits zusätzlich zu
master
Ihrem neuen Commit:Lesen Sie: "Rebase auf den Zweig
amending
, alle Commits zwischenCommit1
(nicht inklusive) undmaster
(inklusive)". Das heißt, Commit2 und Commit3 schneiden das alte Commit1 vollständig aus. Sie könnten sie einfach pflücken, aber dieser Weg ist einfacher.Denken Sie daran, Ihre Zweige aufzuräumen!
quelle
git checkout -b amending Commit1~1
, um das vorherige Commit zu erhaltengit checkout -b amending Commit1
?Basierend auf Dokumentation
Ändern der Nachricht älterer oder mehrerer Festschreibungsnachrichten
Oben wird eine Liste der letzten 3 Commits für den aktuellen Zweig angezeigt. Ändern Sie 3 in etwas anderes, wenn Sie mehr möchten. Die Liste sieht folgendermaßen aus:
Ersetzen Sie pick durch reword vor jeder Commit-Nachricht, die Sie ändern möchten. Angenommen, Sie ändern das zweite Commit in der Liste. Ihre Datei sieht folgendermaßen aus:
Speichern und schließen Sie die Festschreibungslistendatei. Daraufhin wird ein neuer Editor angezeigt, mit dem Sie Ihre Festschreibungsnachricht ändern, die Festschreibungsnachricht ändern und speichern können.
Finaly Force-Push die geänderten Commits.
quelle
Vollständig nicht interaktiver Befehl (1)
Ich dachte nur, ich würde einen Alias teilen, den ich dafür verwende. Es basiert auf einer nicht interaktiven interaktiven Basis. Führen Sie diesen Befehl aus, um es Ihrem Git hinzuzufügen (Erklärung unten):
Der größte Vorteil dieses Befehls ist die Tatsache, dass es kein Vim ist .
(1) da es natürlich keine Konflikte während der Rebase gibt
Verwendungszweck
Der Name
amend-to
scheint meiner Meinung nach angemessen. Vergleichen Sie den Fluss mit--amend
:Erläuterung
git config --global alias.<NAME> '!<COMMAND>'
- Erstellt einen globalen Git-Alias mit dem Namen<NAME>
, der einen Nicht-Git-Befehl ausführt<COMMAND>
f() { <BODY> }; f
- eine "anonyme" Bash-Funktion.SHA=`git rev-parse "$1"`;
- konvertiert das Argument in eine Git-Revision und weist das Ergebnis einer Variablen zuSHA
git commit --fixup "$SHA"
- Fixup-Commit fürSHA
. Siehegit-commit
DokumenteGIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^"
git rebase --interactive "$SHA^"
Teil wurde durch andere Antworten abgedeckt.--autosquash
wird in Verbindung mit verwendetgit commit --fixup
. Weitere Informationen finden Sie in dengit-rebase
DokumentenGIT_SEQUENCE_EDITOR=true
macht das Ganze nicht interaktiv. Diesen Hack habe ich aus diesem Blogbeitrag gelernt .quelle
amend-to
bereitgestellte Dateien verarbeiten:git config --global alias.amend-to '!f() { SHA=
git rev-parse "$ 1"; git stash -k && git commit --fixup "$SHA" && GIT_SEQUENCE_EDITOR=true git rebase --interactive --autosquash "$SHA^" && git stash pop; }; f'
Automatisierte interaktive Rebase-Bearbeitung, gefolgt von Commit-Revert, bereit für eine Überarbeitung
Ich habe festgestellt, dass ich ein Commit in der Vergangenheit häufig genug repariert habe, dass ich ein Skript dafür geschrieben habe.
Hier ist der Workflow:
Dadurch werden Sie an dem Commit abgelegt, den Sie bearbeiten möchten.
Korrigieren und inszenieren Sie das Commit so, wie Sie es sich gewünscht haben.
(Möglicherweise möchten
git stash save
Sie Dateien behalten, die Sie nicht festschreiben.)Wiederholen Sie das Commit mit
--amend
z.Schließen Sie die Rebase ab:
Damit das oben genannte funktioniert, fügen Sie das folgende Skript in eine ausführbare Datei ein, die
git-commit-edit
irgendwo in Ihrem Verzeichnis aufgerufen wird$PATH
:quelle
Kam zu diesem Ansatz (und es ist wahrscheinlich genau das gleiche wie die Verwendung von interaktiver Rebase), aber für mich ist es ziemlich einfach.
Hinweis: Ich präsentiere diesen Ansatz, um zu veranschaulichen, was Sie tun können, anstatt eine alltägliche Alternative zu sein. Da es viele Schritte hat (und möglicherweise einige Einschränkungen.)
Angenommen, Sie möchten das Commit ändern
0
und sind gerade aktivfeature-branch
Kasse zu diesem Commit und erstelle ein
quick-branch
. Sie können Ihren Feature-Zweig auch als Wiederherstellungspunkt klonen (bevor Sie beginnen).Sie werden jetzt so etwas haben:
Bühnenwechsel, alles andere verstauen.
Übernehmen Sie die Änderungen und checken Sie zurück zu
feature-branch
Sie werden jetzt so etwas haben:
Rebase
feature-branch
aufquick-branch
(lösen Konflikte auf dem Weg). Stash auftragen und entfernenquick-branch
.Und am Ende haben Sie:
Git wird die 0-Festschreibung beim erneuten Basieren nicht duplizieren (obwohl ich nicht wirklich sagen kann, inwieweit).
Hinweis: Alle Commit-Hashes werden ab dem Commit geändert, den wir ursprünglich ändern wollten.
quelle
Um einen nicht interaktiven Befehl zu erhalten, fügen Sie ein Skript mit diesem Inhalt in Ihren PFAD ein:
Verwenden Sie es, indem Sie Ihre Änderungen (mit
git add
) bereitstellen und dann ausführengit fixup <commit-to-modify>
. Natürlich bleibt es interaktiv, wenn Konflikte auftreten.quelle
git stash
+rebase
AutomatisierungWenn ich ein altes Commit für Gerrit-Überprüfungen häufig ändern muss, habe ich Folgendes getan:
GitHub stromaufwärts .
Verwendungszweck:
git add
wenn bereits im Repogit-amend-old $old_sha
Ich mag das vorbei,
--autosquash
da es andere nicht verwandte Fixups nicht zerquetscht.quelle
git amend
, um Änderungen an einem bestimmten Commit mit dem aktuellen Stash anzuwenden, sehr clever!Ich habe das gelöst,
1) durch Erstellen eines neuen Commits mit Änderungen, die ich möchte.
2) Ich weiß, welches Commit ich brauche, um es zusammenzuführen. Das ist Commit 3.
Daher steht
git rebase -i HEAD~4
# 4 für das Commit der letzten 4 (hier steht Commit 3 auf dem 4. Platz).3) In der interaktiven Rebase befindet sich das letzte Commit unten. es wird gleich aussehen,
4) Hier müssen wir das Commit neu anordnen, wenn Sie mit einem bestimmten zusammenführen möchten. es sollte so sein,
Nach der Neuanordnung müssen Sie ersetzen
p
pick
durchf
( Fixup wird ohne Festschreibungsnachricht zusammengeführt) oders
( Squash- Zusammenführung mit Festschreibungsnachricht kann sich zur Laufzeit ändern)und dann rette deinen Baum.
Jetzt mit vorhandenem Commit zusammenführen.
quelle
Die beste Option ist die Verwendung des Befehls "Interaktiver Rebase" .
Wie benutzt man nun diesen Befehl?
-i
stehen für "interaktiv" . Beachten Sie, dass Sie eine Rebase im nicht interaktiven Modus durchführen können. Ex:HEAD
Gibt Ihren aktuellen Standort an (kann auch Filialname oder Commit-SHA sein). Das~n
bedeutet "n beforeé", alsoHEAD~n
die Liste der "n" Commits vor dem, auf dem Sie sich gerade befinden.git rebase
hat andere Befehle wie:p
oderpick
festzuhalten, wie es ist.r
oderreword
: um den Inhalt des Commits beizubehalten, aber die Commit-Nachricht zu ändern.s
odersquash
: um die Änderungen dieses Commits mit dem vorherigen Commit (dem darüber liegenden Commit in der Liste) zu kombinieren.... usw.
Hinweis: Es ist besser, Git mit Ihrem Code-Editor zum Laufen zu bringen, um die Arbeit zu vereinfachen. Wenn Sie beispielsweise visuellen Code verwenden, können Sie diesen hinzufügen
git config --global core.editor "code --wait"
. Oder Sie können in Google suchen, wie Sie Ihren bevorzugten Code-Editor mit GIT verknüpfen können.Beispiel von
git rebase
Ich wollte die letzten 2 Commits ändern, die ich gemacht habe, also verarbeite ich so:
Jetzt
git rebase
ändere ich die 2 letzten Commit-Nachrichten:$git rebase -i HEAD~2
Es öffnet den Code-Editor und zeigt Folgendes:Da möchte ich die Commit-Nachricht für diese 2 Commits ändern. Also werde ich tippen
r
oderreword
anstelle vonpick
. Speichern Sie dann die Datei und schließen Sie die Registerkarte. Beachten Sie, dass diesrebase
in einem mehrstufigen Prozess ausgeführt wird. Der nächste Schritt besteht darin, die Nachrichten zu aktualisieren. Beachten Sie auch, dass die Festschreibungen in umgekehrter chronologischer Reihenfolge angezeigt werden, sodass die letzte Festschreibung in dieser und die erste Festschreibung in der ersten Zeile usw. angezeigt wird.Aktualisieren Sie die Nachrichten: Aktualisieren Sie die erste Nachricht:
Speichern und schließen Bearbeiten Sie die zweite Nachricht
speichern und schließen.
Am Ende der Rebase erhalten Sie eine solche Nachricht: Dies
Successfully rebased and updated refs/heads/documentation
bedeutet, dass Sie erfolgreich sind. Sie können die Änderungen anzeigen:Ich wünschte, das könnte den neuen Benutzern helfen :).
quelle
Für mich war es das Entfernen einiger Anmeldeinformationen aus einem Repo. Ich habe versucht, neu zu gründen, und bin dabei auf eine Menge scheinbar nicht zusammenhängender Konflikte gestoßen, als ich versucht habe, neu zu gründen - weiterzumachen. Versuchen Sie nicht, sich neu zu gründen, sondern verwenden Sie das Tool BFG (Brew Install Bfg) auf dem Mac.
quelle
Wenn Sie die Commits noch nicht gepusht haben, können Sie mit zu einem vorherigen Commit zurückkehren
git reset HEAD^[1,2,3,4...]
Zum Beispiel
Hoppla, ich habe vergessen, file2 zum ersten Commit hinzuzufügen ...
Dadurch wird Datei2 zum ersten Commit hinzugefügt.
quelle
Nun, diese Lösung mag sehr albern klingen, kann Sie aber unter bestimmten Bedingungen retten.
Ein Freund von mir hat gerade versehentlich einige sehr große Dateien festgeschrieben (vier automatisch generierte Dateien zwischen 3 GB und 5 GB) und dann einige zusätzliche Code-Commits durchgeführt, bevor er das Problem erkannte, das
git push
nicht mehr funktionierte!Die Dateien wurden aufgelistet,
.gitignore
aber nach dem Umbenennen des Containerordners wurden sie verfügbar gemacht und festgeschrieben! Und jetzt gab es noch ein paar weitere Commits des Codes, die jedochpush
für immer ausgeführt wurden (beim Versuch, GB Daten hochzuladen!) Und schließlich aufgrund der Dateigrößenbeschränkungen von Github fehlschlagen würden .Das Problem mit interaktiver Rebase oder Ähnlichem war, dass sie sich mit dem Stöbern in diesen riesigen Dateien befassen und ewig brauchen würden, um etwas zu tun. Trotzdem waren wir uns nach fast einer Stunde in der CLI nicht sicher, ob die Dateien (und Deltas) tatsächlich aus dem Verlauf entfernt oder einfach nicht in den aktuellen Commits enthalten sind. Der Push funktionierte auch nicht und mein Freund steckte wirklich fest.
Die Lösung, die ich gefunden habe, war:
~/Project-old
.~/Project
).cp -r
die Dateien von~/Project-old
Ordner zu~/Project
.mv
bearbeitet und enthalten sind.gitignore
ordnungsgemäß enthalten sind..git
Ordner im kürzlich geklonten Ordner nicht überschreiben~/Project
von dem alten . Hier leben die Protokolle der problematischen Geschichte!push
.Das größte Problem bei dieser Lösung besteht darin, dass einige Dateien manuell kopiert werden und alle kürzlich durchgeführten Commits zu einem zusammengeführt werden (offensichtlich mit einem neuen Commit-Hash). B.
Die großen Vorteile sind, dass es in jedem Schritt sehr klar ist, sowohl für große als auch für sensible Dateien hervorragend geeignet ist und keine Spuren in der Geschichte hinterlässt!
quelle