So fügen Sie eine geänderte Datei zu einem älteren (nicht letzten) Commit in Git hinzu

461

Ich habe in der letzten Stunde einige Dinge geändert und sie Schritt für Schritt festgeschrieben, aber ich habe gerade festgestellt, dass ich vor einigen Festschreibungen vergessen habe, eine geänderte Datei hinzuzufügen.

Das Protokoll sieht folgendermaßen aus:

    GIT TidyUpRequests u:1 d:0> git log 
    commit fc6734b6351f6c36a587dba6dbd9d5efa30c09ce 
    Author: David Klein <> 
    Date:   Tue Apr 27 09:43:55 2010 +0200

        The Main program now tests both Webservices at once

    commit 8a2c6014c2b035e37aebd310a6393a1ecb39f463 
    Author: David Klein <>
    Date:   Tue Apr 27 09:43:27 2010 +0200

        ISBNDBQueryHandler now uses the XPath functions from XPath.fs too

    commit 06a504e277fd98d97eed4dad22dfa5933d81451f 
    Author: David Klein <> 
    Date:   Tue Apr 27 09:30:34 2010 +0200

        AmazonQueryHandler now uses the XPath Helper functions defined in XPath.fs

    commit a0865e28be35a3011d0b6091819ec32922dd2dd8 <--- changed file should go here
    Author: David Klein <> 
    Date:   Tue Apr 27 09:29:53 2010 +0200

        Factored out some common XPath Operations

Irgendwelche Ideen?

leen
quelle
1
Im Wesentlichen ein Duplikat von Wie ändere ich ein bestimmtes Commit?
Dan Dascalescu

Antworten:

694

Verwenden Sie git rebase. Speziell:

  1. Verwenden git stashSie diese Option , um die Änderungen zu speichern, die Sie hinzufügen möchten.
  2. Verwenden Sie git rebase -i HEAD~10(oder wie viele Commits Sie zurück sehen möchten).
  3. Markieren Sie das betreffende Commit ( a0865...) zum Bearbeiten, indem Sie das Wort pickam Zeilenanfang in ändern edit. Löschen Sie die anderen Zeilen nicht, da dies die Commits löschen würde. [^ Vimnote]
  4. Speichern Sie die Rebase-Datei, und git kehrt zur Shell zurück und wartet, bis Sie das Commit behoben haben.
  5. Pop das Versteck mit git stash pop
  6. Fügen Sie Ihre Datei mit hinzu git add <file>.
  7. Ändern Sie das Commit mit git commit --amend --no-edit.
  8. Tun Sie eine, git rebase --continuedie den Rest Ihrer Commits gegen die neue umschreibt.
  9. Wiederholen Sie diesen Vorgang ab Schritt 2, wenn Sie mehr als ein Commit zum Bearbeiten markiert haben.

[^ vimnote]: Wenn Sie verwenden vimdann werden Sie das getroffen haben , um InsertSchlüssel zu bearbeiten, dann Escund geben Sie in :wqdie Datei zu speichern, verlassen Sie den Editor, und die Änderungen zu übernehmen. Alternativ können Sie einen benutzerfreundlichen Git-Commit-Editor mit konfigurierengit config --global core.editor "nano" .

Greg Hewgill
quelle
23
Was ist, wenn Sie nicht bereitgestellte Änderungen haben, die Sie zur Bearbeitung hinzufügen möchten? Wenn ich sie verstauen würde, könnte ich nicht git add.
Sam
15
Sam Sie können die Änderungen einfach aufheben, während auf dem fraglichen Commit, es wird gut funktionieren.
Omnikron
17
Hinweis: Wenn Sie das Commit mit markieren edit, LÖSCHEN Sie die anderen in der Datei aufgeführten Commits NICHT. In diesem Fall werden die Commits gelöscht und Sie müssen diese Schritte ausführen , um sie zurückzubekommen.
David Tuite
2
In Bezug auf das, was @DavidTuite gesagt hat, ist es meine Gewohnheit, wenn ich Dinge auf Git mache, bei denen ich nicht sicher bin, wie es ausgehen wird, einen "branchname-ref" -Zweig zu erstellen, um den aktuellen Status der Timeline zu speichern, falls ich etwas vermassle. Wenn ich fertig bin, lösche ich es.
Raphael
1
Fügen Sie in Schritt 6 die. (Punkt) im Befehl. Richtiger Befehl:git add .
Tom
323

Um „fix“ ein alte mit einer kleinen Änderung zu übernehmen, ohne die Botschaft der alten begehen begehen, wo OLDCOMMITist so etwas wie 091b73a:

git add <my fixed files>
git commit --fixup=OLDCOMMIT
git rebase --interactive --autosquash OLDCOMMIT^

Sie können auch git commit --squash=OLDCOMMITdie alte Festschreibungsnachricht während der erneuten Basis bearbeiten.


  • git rebase --interactiveruft einen Texteditor auf (der konfiguriert werden kann ), um die Rebase-Anweisungssequenz zu bestätigen (oder zu bearbeiten) . Die Datei enthält Informationen zu Änderungen der Rebase-Anweisungen . Speichern Sie einfach den Editor und beenden Sie ihn ( :wqinvim ), um mit der Rebase fortzufahren.
  • --autosquashlegt automatisch alle --fixup=OLDCOMMITCommits in der gewünschten Reihenfolge ab. Beachten Sie, dass dies --autosquashnur gültig ist, wenn die --interactiveOption verwendet wird.
  • Das ^in OLDCOMMIT^bedeutet, dass es sich um einen Verweis auf das Commit kurz zuvor handelt OLDCOMMIT.

Die obigen Schritte eignen sich zur Überprüfung und / oder Änderung der Rebase-Anweisungssequenz. Sie können den interaktiven Rebase-Texteditor jedoch auch überspringen / automatisieren, indem Sie:

Siehe git commit und git rebase . Wie immer sollten Sie beim Umschreiben des Git-Verlaufs nur Commits korrigieren oder quetschen, die Sie noch nicht für andere veröffentlicht haben (einschließlich zufälliger Internetbenutzer und Build-Server).

Joel Purra
quelle
18
Viel klarer als die anderen Optionen, und es funktionierte wie ein Zauber
Chris Mitchelmore
5
@Jonah: Der Editor wird nicht geöffnet, um die Commit-Nachricht zu bearbeiten , sondern um die Rebase-Schritte zu bestätigen (oder zu bearbeiten) . Es kann nicht vermieden werden; --autosquashist nur gültig, wenn die --interactiveOption verwendet wird .
Joel Purra
5
Mit dieser Lösung stecke ich fest und zeige VIM. Mein Problem ist, ich weiß nicht, wie man VIM benutzt. Wie zum Teufel komme ich da raus, wie kann ich dieses Ding kontrollieren, das so verwirrend.
Neon Warge
2
@NeonWarge: Der Editor Ihrer Wahl kann beispielsweise mit konfiguriert werden git config --global core.editor "pico". Es gibt verschiedene andere Möglichkeiten, um git zu konfigurieren und / oder den Standardeditor usw. Ihres Systems zu ändern .
Joel Purra
2
eine Zeile netter Alias hier
idanp
61

Mit Git 1.7 gibt es eine sehr einfache Möglichkeit git rebase:

Stellen Sie Ihre Dateien bereit:

git add $files

Erstellen Sie ein neues Commit und verwenden Sie die Commit-Nachricht Ihres "defekten" Commits erneut

git commit -c master~4

fixup!in der Betreffzeile voranstellen (oder squash!wenn Sie das Commit (Nachricht) bearbeiten möchten):

fixup! Factored out some common XPath Operations

Verwenden Sie git rebase -i --autosquashdiese Option, um Ihr Commit zu korrigieren

stricken
quelle
2
+1. Gute Verwendung der neuen Fixup-Direktive (1.7+): stackoverflow.com/questions/2302736/trimming-git-checkins/…
VonC
@knittl Ich habe Ihre Methode ausprobiert, um eine andere Datei zu einem alten Commit von mir hinzuzufügen (nicht gepusht), aber beim erneuten Basieren erhalte ich You asked me to rebase without telling me which branch you want to rebase against, and 'branch.master.merge'und wenn ich sie dann verwende , erhalte git rebase -i --autosquashich nur eine noopBetreffzeile, die das Commit auf sich selbst neu basiert. Irgendeine Idee, was ich falsch mache?
Oschrenk
7
@oschrenk: Sie müssen ein Commit angeben, auf das Sie zurückgreifen möchten, z. B.git rebase -i --autosquash HEAD~10
knittl
1
Gute Antwort, aber ich musste auch ein Commit hinzufügen, gegen das ich mich neu stützen konnte. Wäre toll wenn du es aktualisieren könntest.
Paul Odeon
@ PaulOdeon: Ich verstehe deine Frage nicht. Was versuchst du zu tun und wo hast du Probleme?
Knittl
8

Sie können eine rebase --interactiveSitzung versuchen , um Ihr altes Commit zu ändern (vorausgesetzt, Sie haben diese Commits noch nicht auf ein anderes Repo übertragen).

Manchmal ist die Sache in b.2 behoben. kann nicht an das nicht ganz perfekte Commit geändert werden, das es behebt, da dieses Commit tief in einer Patch-Serie vergraben ist .
Genau dafür ist die interaktive Rebase gedacht: Verwenden Sie sie nach vielen "a" und "b", indem Sie Commits neu anordnen und bearbeiten und mehrere Commits zu einem zusammenfassen.

Beginnen Sie mit dem letzten Commit, das Sie unverändert beibehalten möchten:

git rebase -i <after-this-commit>

Ein Editor wird mit allen Commits in Ihrem aktuellen Zweig gestartet (Merge-Commits werden ignoriert), die nach dem angegebenen Commit erfolgen.
Sie können die Commits in dieser Liste nach Herzenslust neu anordnen und entfernen. Die Liste sieht mehr oder weniger so aus:

pick deadbee The oneline of this commit
pick fa1afe1 The oneline of the next commit
...

Die Online-Beschreibungen dienen ausschließlich Ihrem Vergnügen. git rebase betrachtet sie nicht, sondern die Commit-Namen (in diesem Beispiel "deadbee" und "fa1afe1"). Löschen oder bearbeiten Sie die Namen also nicht.

Indem Sie den Befehl "pick" durch den Befehl "edit" ersetzen, können Sie git rebase anweisen, nach dem Anwenden dieses Commits zu stoppen, damit Sie die Dateien und / oder die Commit-Nachricht bearbeiten, das Commit ändern und das Rebasing fortsetzen können .

VonC
quelle