Wie ändere ich das vergangene Commit, um eine fehlende Datei einzuschließen?

98

Ich habe eine Änderung festgeschrieben und vergessen, dem Änderungssatz eine Datei hinzuzufügen. Nach anderen Commits wurde mir klar, dass die Datei jetzt in einem HEAD^4Commit fehlt .

Wie schreibe ich ein vorheriges Commit neu, um die fehlende Datei einzuschließen?

kolrie
quelle
Hast du diese 4 Commits gepusht?
MVP
@mvp nein, sie befinden sich nur in meinem lokalen Git-Repository.
Kolrie

Antworten:

53

Verwenden git rebase --interactive HEAD~4und setzen Sie die editOption für das Commit, das Sie ändern möchten.

Denken Sie daran, dass Sie Commits, die an das Remote-Repository gesendet werden, nicht auf diese Weise ändern sollten . In diesem Fall ist es besser, ein neues Commit mit fehlender Datei hinzuzufügen.

Rafał Rawicki
quelle
Vielen Dank. Ist das auch dann der Fall, wenn ich der einzige Benutzer des Remote-Repos bin? Würde es mir nicht erlauben, git push -fwenn ich sicher bin, dass sich der Upstream nicht geändert hat?
Kolrie
1
Wenn Sie der einzige Benutzer des Remote-Repos sind, ist es in Ordnung, den erzwungenen Push auszuführen.
Rafał Rawicki
7
Ich denke, diese Anweisungen sind nicht detailliert genug. Beim ersten Versuch wurde mir gesagt: "Kann nicht wiederhergestellt werden: Ihr Index enthält nicht festgeschriebene Änderungen." Ich hatte adddie fehlenden Dateien bereits -ed, also habe ich ein Commit mit "xxx" als Nachricht durchgeführt. Dann habe ich den Rebase-Befehl ausgeführt und das Commit "xxx" von "pick" in "edit" geändert. Dann habe ich "git rebase --continue" gemacht. Wenn ich mir jetzt den Verlauf ansehe, habe ich "xxx" als letztes Commit, und das frühere Commit, zu dem ich sie hinzufügen wollte, ist unverändert! Ich frage mich, wo mein Fehler war?
Darren Cook
2
Durch das Quetschen des letzten Commits wird die Datei nicht in HEAD ~ 4 abgelegt.
Justin
1
git add editFiles; git commit -m "Blah"; Git Rebase -i HEAD ~ 5; // Da jetzt ein neues Commit hinzugefügt wurde, mussten wir mit 5 statt 4 neu basieren. Verschieben Sie nun das Commit "Blah" in die zweite Zeile und ändern Sie es von "Pick" in "s" (Squash), wodurch das Commit mit HEAD ~ gequetscht wird 5 als Befehle werden von oben nach unten ausgeführt
zstring
273

Mir ist klar, dass Leute googeln und hierher kommen können, um eine einfachere Antwort zu finden: Was wäre, wenn es nur das letzte Commit wäre? (Die Frage von OP betrifft die Behebung des 4. Commits in der Geschichte.)

Wenn Sie festschreiben und feststellen, dass Sie vergessen haben, sofort eine Datei hinzuzufügen , gehen Sie einfach wie folgt vor:

# edited file-that-i-remember.txt
git add file-that-i-remember.txt
git commit

# realize you forgot a file
git add file-that-i-forgot.txt
git commit --amend --no-edit

Wo --no-editwird die gleiche Commit-Nachricht aufbewahrt.

Kinderleicht!

Dr. Beco
quelle
21
Das ist die Antwort.
Adam Bittlingmayer
5
Erwähnenswert, wenn die Commits nicht auf die Fernbedienung übertragen werden.
Ram Patra
1
Ja, es ist erwähnenswert hier in den Kommentaren: Es ist für die Verwendung vor dem Push . Danke, dass du darauf hingewiesen hast.
Dr. Beco
2
Ein Hinweis ist , dass die Commits vor und nach --amendhaben unterschiedliche Hashes
sonlexqt
5
Danke, aber es kann nicht sein: OP gefragt HEAD^4. Es ist in Ordnung, so wie es ist, nur als Nachtrag als Referenz. ;)
Dr. Beco
11

Wenn Sie diese 4 Commits NICHT gepusht haben, können Sie dies wie folgt tun:

Erstellen Sie Patch-Dateien für alle diese Commits:

git format-patch -4

Rücklauf um 4 Commits:

git reset --hard HEAD~4

Fehlende Datei hinzufügen:

git add missing-file

Verpflichte es mit --amend:

git commit --amend

Wenden Sie alle gespeicherten Patches wieder an:

git am *.patch

Wenn Sie gedrückt haben, sollten Sie diese Methode NICHT verwenden. Geben Sie stattdessen einfach Ihren Fehler zu und erstellen Sie zusätzlich zu HEAD ein weiteres Commit, das dieses Problem behebt.

mvp
quelle
Wenn Sie dies Schritt für Schritt tun möchten, ist es einfacher, Commits nach dem geänderten auszuwählen, als sie als Patch zu exportieren.
Rafał Rawicki
1
Das ist Geschmackssache. Ich mag git format-patch/ git amviel besser. Am wichtigsten ist, dass Sie mehr Vertrauen haben, wenn Sie etwas vermasseln - Commit, das als Patch in einer physischen Datei gespeichert ist, ist Ihr bestes Sicherheitsnetz.
MVP
Das wahre Vertrauen liegt in der Tat, dass Sie bei der Arbeit mit einem Git-Repository niemals etwas entfernen. Alte Commits sind verfügbar, bis Sie laufen git gc:)
Rafał Rawicki
Dies ist trivial und offensichtlich für Sie und mich. Aber für Benutzer, die gerade erst anfangen und wahrscheinlich nichts über Git verstehen - diese Tatsache ist überhaupt nicht offensichtlich.
MVP
2
Diese Anweisungen schienen langwierig, waren aber recht einfach und leicht zu befolgen. Vielen Dank. (Ich hatte gerade einen letzten Schritt: rm *.patch)
Darren Koch
9

Obwohl die akzeptierte Antwort korrekt ist, fehlen detaillierte Anweisungen zum Bearbeiten eines Commits während eines Rebase-Prozesses.

  • Starten Sie zunächst einen Rebase-Prozess:

    git rebase --interactive HEAD~4
    
  • Eine Liste der Commits wird angezeigt. Wählen Sie ein Commit aus, das Sie bearbeiten möchten, indem Sie das Wort pickin ändern , editund speichern Sie die Datei.

  • Nehmen Sie die erforderlichen Änderungen in Ihrem Code vor (denken Sie daran, git addneue Dateien aufzurufen ).

  • Nachdem alle Änderungen vorgenommen wurden, git commit --amendwird ausgegeben - dies ändert ein Commit, das als gekennzeichnet istedit

  • Rufen Sie auf git rebase --continue, um den Vorgang abzuschließen (wenn mehr Commits als gekennzeichnet sind edit, müssen die obigen Schritte wiederholt werden).

Wichtige Notizen:

  • Entfernen pickSie KEINE Linien, die als nicht bearbeitet markiert sind - lassen Sie sie unverändert. Das Löschen dieser Zeilen führt zum Löschen verwandter Commits

  • GIT zwingt Sie stashvor dem erneuten Basieren, wenn Ihr Arbeitsverzeichnis nicht sauber ist. Sie können jedoch git stash pop / git stash applywährend des Rebases diese Änderungen (dh Änderungen, die vor dem Starten des Rebase-Prozesses gespeichert wurden) in ein Commit ändern, das als gekennzeichnet istedit

  • Wenn ein Fehler aufgetreten ist und Sie Änderungen rückgängig machen möchten, die während des Rebase-Vorgangs vor dessen Abschluss vorgenommen wurden (dh Sie möchten auf den Punkt zurückgreifen, bevor Sie den Rebase starten), verwenden Sie git rebase --abort- lesen Sie auch: So brechen Sie einen interaktiven Rebase ab, wenn --abort dies nicht tut. nicht arbeiten?

  • Wie in der akzeptierten Antwort gesagt:

    Denken Sie daran, dass Sie Commits, die an das Remote-Repository gesendet werden, nicht auf diese Weise ändern sollten. In diesem Fall ist es besser, ein neues Commit mit fehlender Datei hinzuzufügen.

    Die Antwort, warum, ist im Git-Buch (Absatz mit dem Titel " The Perils of Rebasing "):

    Setzen Sie keine Commits zurück, die außerhalb Ihres Repositorys vorhanden sind.

    Wenn Sie diese Richtlinie befolgen, wird es Ihnen gut gehen. Wenn Sie dies nicht tun, werden die Leute Sie hassen und Sie werden von Freunden und Familie verachtet.

    Wenn Sie Inhalte neu erstellen, geben Sie vorhandene Commits auf und erstellen neue, die ähnlich, aber unterschiedlich sind. Wenn Sie Commits irgendwo pushen und andere sie nach unten ziehen und die Arbeit darauf aufbauen, und Sie diese Commits dann mit Git Rebase neu schreiben und wieder nach oben drücken, müssen Ihre Mitarbeiter ihre Arbeit neu zusammenführen, und die Dinge werden chaotisch, wenn Sie es versuchen ziehe ihre Arbeit zurück in deine.

    [...]

dominik
quelle