Ich habe mit einem Freund an einem Projekt gearbeitet und er hat eine Reihe von Dateien bearbeitet, die nicht hätten bearbeitet werden dürfen. Irgendwie habe ich seine Arbeit in meine integriert, entweder als ich sie gezogen habe oder als ich versucht habe, nur die gewünschten Dateien auszuwählen. Ich habe lange gesucht und gespielt und versucht herauszufinden, wie die Commits entfernt werden können, die die Änderungen an diesen Dateien enthalten. Es scheint ein Fehler zwischen Zurücksetzen und Wiederherstellen zu sein, und es gibt keine einfachen Beispiele Die Ärzte gehen davon aus, dass ich mehr weiß als ich.
Hier ist eine vereinfachte Version der Frage:
Wie entferne ich in dem folgenden Szenario Commit 2?
$ mkdir git_revert_test && cd git_revert_test
$ git init
Initialized empty Git repository in /Users/josh/deleteme/git_revert_test/.git/
$ echo "line 1" > myfile
$ git add -A
$ git commit -m "commit 1"
[master (root-commit) 8230fa3] commit 1
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 myfile
$ echo "line 2" >> myfile
$ git commit -am "commit 2"
[master 342f9bb] commit 2
1 files changed, 1 insertions(+), 0 deletions(-)
$ echo "line 3" >> myfile
$ git commit -am "commit 3"
[master 1bcb872] commit 3
1 files changed, 1 insertions(+), 0 deletions(-)
Das erwartete Ergebnis ist
$ cat myfile
line 1
line 3
Hier ist ein Beispiel dafür, wie ich versucht habe, zurückzukehren
$ git revert 342f9bb
Automatic revert failed. After resolving the conflicts,
mark the corrected paths with 'git add <paths>' or 'git rm <paths>'
and commit the result.
quelle
Antworten:
Der Algorithmus, den Git bei der Berechnung der zurückzusetzenden Diffs verwendet, erfordert dies
Die Definition von "benachbart" basiert auf der Standardanzahl von Zeilen aus einem Kontextdifferenz, die 3 ist. Wenn also 'myfile' wie folgt konstruiert wurde:
Dann funktioniert alles wie erwartet.
Die zweite Antwort war sehr interessant. Es gibt eine Funktion namens Revert Strategy, die noch nicht offiziell veröffentlicht wurde (obwohl sie in Git v1.7.2-rc2 verfügbar ist). Sie können git wie folgt aufrufen:
und es sollte einen besseren Job machen, um herauszufinden, was Sie meinten. Ich weiß weder die Liste der verfügbaren Strategien noch die Definition einer Strategie.
quelle
perl -p
ist nützlich , um die Schleife und sehr kurz (eine Zeile) Schreiben von Programmen übergeben ihre Eingabe an den Ausgang, ähnlich wie Sed.perl -i
ist für die Bearbeitung von Dateien verwendet anstelle .perl -e
So senden Sie den auszuwertenden Code .Es gibt vier Möglichkeiten, dies zu tun:
Sauberer Weg, Zurücksetzen, aber Protokollieren des Zurücksetzens:
Auf harte Weise entfernen Sie insgesamt nur das letzte Commit:
Hinweis: Vermeiden
git reset --hard
Sie es, alle Änderungen in Dateien seit dem letzten Festschreiben zu verwerfen. Wenn--soft
es nicht funktioniert, versuchen Sie es lieber mit--mixed
oder--keep
.Rebase (zeige das Protokoll der letzten 5 Commits an und lösche die Zeilen, die du nicht willst, oder ordne sie neu an oder quetsche mehrere Commits in einem oder mache alles andere, was du willst. Dies ist ein sehr vielseitiges Tool):
Und wenn ein Fehler gemacht wird:
Schnelle Wiederherstellung: Entfernen Sie nur ein bestimmtes Commit mit seiner ID:
Alternativen: Sie können auch versuchen:
Noch eine Alternative:
Als letzten Ausweg können Sie diese sehr schnelle Open-Source-Anwendung verwenden: reposurgeon , wenn Sie die volle Freiheit bei der Bearbeitung des Verlaufs benötigen (z. B. weil Sie mit git nicht bearbeiten können, was Sie möchten) .
Hinweis: Natürlich werden alle diese Änderungen lokal vorgenommen. Anschließend sollten Sie
git push
die Änderungen auf die Fernbedienung anwenden. Und falls Ihr Repo das Commit nicht entfernen möchte ("kein schneller Vorlauf erlaubt", was passiert, wenn Sie ein bereits übertragenes Commit entfernen möchten), können Siegit push -f
die Änderungen erzwingen.Hinweis 2: Wenn Sie an einem Zweig arbeiten und Push erzwingen müssen, sollten Sie dies unbedingt vermeiden,
git push --force
da dies andere Zweige überschreiben kann (wenn Sie Änderungen daran vorgenommen haben, auch wenn sich Ihre aktuelle Kasse in einem anderen Zweig befindet). Geben Sie immer den Remote-Zweig an, wenn Sie Push erzwingen :git push --force origin your_branch
.quelle
git rebase -i HEAD~5
arbeitete für mich. Dann habe ich nur die Commits entfernt, die ich nicht brauchte, und konnte das Problem in weniger als 30 Sekunden lösen. Danke dir.Hier ist eine einfache Lösung:
(Hinweis:
x
ist die Anzahl der Commits)Beim Ausführen wird die Editor-Datei geöffnet. Geben Sie
drop
neben Ihrem Commit ein.Wenn Sie Vim nicht kennen, klicken Sie einfach auf jedes Wort, das Sie bearbeiten möchten, und drücken Sie dann die Taste "I" (für den Einfügemodus). Wenn Sie mit der Eingabe fertig sind, drücken Sie die Taste "esc", um den Einfügemodus zu verlassen.
und fertig, Sie sind fertig ... Synchronisieren Sie einfach das Git-Dashboard und die Änderungen werden auf Remote übertragen.
Wenn sich das von Ihnen abgelegte Commit bereits auf der Fernbedienung befand, müssen Sie Push erzwingen. Da --force als schädlich angesehen wird , verwenden Sie
git push --force-with-lease
.quelle
Sie haben die Wahl zwischen
Sie sollten wählen (1), ob die fehlerhafte Änderung von jemand anderem übernommen wurde, und (2), ob der Fehler auf einen privaten, nicht übertragenen Zweig beschränkt ist.
Git Revert ist ein automatisiertes Tool (1), das ein neues Commit erstellt und einige vorherige Commits rückgängig macht. Sie werden den Fehler und das Entfernen im Projektverlauf sehen, aber Personen, die aus Ihrem Repository ziehen, werden beim Aktualisieren keine Probleme haben. In Ihrem Beispiel funktioniert dies nicht automatisiert. Sie müssen daher 'myfile' bearbeiten (um Zeile 2 zu entfernen), den Konflikt ausführen
git add myfile
undgit commit
behandeln. Sie erhalten dann vier Commits in Ihrem Verlauf, wobei Commit 4 Commit 2 zurücksetzt.Wenn es niemanden interessiert, dass sich Ihr Verlauf ändert, können Sie ihn neu schreiben und Commit 2 entfernen (Auswahl 2). Der einfache Weg, dies zu tun, ist zu verwenden
git rebase -i 8230fa3
. Dadurch werden Sie in einen Editor verschoben, und Sie können festlegen, dass das fehlerhafte Festschreiben nicht eingeschlossen wird, indem Sie das Festschreiben entfernen (und "Auswahl" neben den anderen Festschreibungsnachrichten beibehalten. Informieren Sie sich über die Konsequenzen, die sich daraus ergeben .quelle
Ansatz 1
Holen Sie sich zuerst den Commit-Hash (Beispiel: 1406cd61), den Sie zurücksetzen müssen. einfache Lösung wird unter Befehl sein,
Wenn Sie nach dem Festschreiben von 1406cd61 weitere Änderungen in Bezug auf 1406cd61-Dateien festgeschrieben haben, funktioniert der obige einfache Befehl nicht. Dann müssen Sie die folgenden Schritte ausführen, nämlich Kirschernte.
Ansatz 2
Bitte folgen Sie den folgenden Aktionen. Da wir --force verwenden, müssen Sie über Administratorrechte für das Git-Repo verfügen, um dies zu tun.
Schritt 1: Suchen Sie das Commit vor dem Commit, das Sie entfernen möchten
git log
Schritt 2: Überprüfen Sie das Commit
git checkout <commit hash>
Schritt 3: Erstellen Sie einen neuen Zweig mit Ihrem aktuellen Checkout-Commit
git checkout -b <new branch>
Schritt 4: Jetzt müssen Sie das Commit nach dem entfernten Commit hinzufügen
git cherry-pick <commit hash>
Schritt 5: Wiederholen Sie nun Schritt 4 für alle anderen Commits, die Sie behalten möchten.
Schritt 6: Sobald alle Commits zu Ihrem neuen Zweig hinzugefügt und festgeschrieben wurden. Überprüfen Sie, ob alles im richtigen Zustand ist und wie vorgesehen funktioniert. Überprüfen Sie noch einmal, ob alles festgeschrieben wurde:
git status
Schritt 7: Wechseln Sie zu Ihrem defekten Zweig
git checkout <broken branch>
Schritt 8: Führen Sie nun einen Hard-Reset für den defekten Zweig auf das Commit durch, bevor Sie den entfernen möchten
git reset --hard <commit hash>
Schritt 9: Führen Sie Ihren festen Zweig in diesen Zweig ein
git merge <branch name>
Schritt 10: Schieben Sie die zusammengeführten Änderungen zurück zum Ursprung. WARNUNG: Dadurch wird das Remote-Repo überschrieben!
git push --force origin <branch name>
Sie können den Vorgang ausführen, ohne einen neuen Zweig zu erstellen, indem Sie Schritt 2 und 3 durch Schritt 8 ersetzen und dann Schritt 7 und 9 nicht ausführen.
quelle
Sie können unerwünschte Commits mit entfernen
git rebase
. Angenommen, Sie haben einige Commits aus dem Themenzweig eines Kollegen in Ihren Themenzweig aufgenommen, aber später entschieden, dass Sie diese Commits nicht möchten.Zu diesem Zeitpunkt öffnet Ihr Texteditor die interaktive Rebase-Ansicht. Beispielsweise
Wenn die Rebase nicht erfolgreich war, löschen Sie den temporären Zweig und versuchen Sie es mit einer anderen Strategie. Fahren Sie andernfalls mit den folgenden Anweisungen fort.
Wenn Sie Ihren Themenzweig auf eine Fernbedienung verschieben, müssen Sie möglicherweise Push erzwingen, da sich der Festschreibungsverlauf geändert hat. Wenn andere an demselben Zweig arbeiten, geben Sie ihnen einen Hinweis.
quelle
Aufgrund anderer Antworten hier war ich etwas verwirrt darüber, wie
git rebase -i
ein Commit entfernt werden kann. Ich hoffe, dass es in Ordnung ist, meinen Testfall hier aufzuschreiben (sehr ähnlich dem OP).Hier ist ein
bash
Skript, das Sie einfügen können, um ein Test-Repository im/tmp
Ordner zu erstellen :An dieser Stelle haben wir eine
file.txt
mit folgenden Inhalten:Zu diesem Zeitpunkt befindet sich HEAD beim 5. Commit, HEAD ~ 1 wäre das 4. - und HEAD ~ 4 wäre das 1. Commit (also würde HEAD ~ 5 nicht existieren). Angenommen, wir möchten das dritte Commit entfernen - wir können diesen Befehl im
myrepo_git
Verzeichnis ausgeben :( Beachten Sie, dass die
git rebase -i HEAD~5
Ergebnisse mit "fatal: Benötigt eine einzelne Revision; ungültiger Upstream-HEAD ~ 5" angezeigt werden . ) Ein Texteditor (siehe Screenshot in der Antwort von @Dennis ) wird mit folgenden Inhalten geöffnet:Wir erhalten also alle Commits seit (aber nicht einschließlich ) unserem angeforderten HEAD ~ 4. Löschen Sie die Zeile
pick 448c212 3rd git commit
und speichern Sie die Datei. Sie erhalten diese Antwort vongit rebase
:Öffnen Sie an dieser Stelle myrepo_git /
folder/file.txt
in einem Texteditor. Sie werden sehen, dass es geändert wurde:Grundsätzlich
git
sieht man, dass, als HEAD zum 2. Commit kam, Inhalt vonaaaa
+ warbbbb
; und dann hat es einen Patch mitcccc
+ hinzugefügt,dddd
den es nicht an den vorhandenen Inhalt anhängen kann.Also hier
git
können Sie sich nicht entscheiden - es ist Sie , die eine Entscheidung zu treffen hat: durch die 3. Entfernen begehen, können Sie entweder die Änderungen , indem sie eingeführt halten (hier die Liniecccc
) - oder eben nicht. Wenn Sie dies nicht tun, entfernen Sie einfach die zusätzlichen Zeilen - einschließlich dercccc
- infolder/file.txt
einem Texteditor, damit es so aussieht:... und dann speichern
folder/file.txt
. Jetzt können Sie die folgenden Befehle immyrepo_git
Verzeichnis ausgeben :Ah - so um Marke , dass wir den Konflikt gelöst haben, wir müssen
git add
dasfolder/file.txt
, bevor Siegit rebase --continue
:Hier öffnet sich wieder ein Texteditor, der die Zeile anzeigt
4th git commit
- hier haben wir die Möglichkeit, die Commit-Nachricht zu ändern (die in diesem Fall sinnvoll in4th (and removed 3rd) commit
oder ähnlich geändert werden könnte ). Angenommen, Sie möchten nicht - verlassen Sie einfach den Texteditor, ohne zu speichern. Sobald Sie das tun, erhalten Sie:An diesem Punkt haben Sie jetzt eine solche Historie (die Sie auch mit say
gitk .
oder anderen Tools überprüfen können) des Inhalts vonfolder/file.txt
(mit anscheinend unveränderten Zeitstempeln der ursprünglichen Commits):Und wenn wir uns zuvor entschlossen hätten, die Zeile
cccc
beizubehalten (der Inhalt des 3. Git-Commits, den wir entfernt haben), hätten wir Folgendes gehabt:Nun, dies war die Art von Lektüre, von der ich gehofft hatte, dass ich sie gefunden hätte, um herauszufinden, wie das
git rebase
Löschen von Commits / Revisionen funktioniert. also hoffe es könnte auch anderen helfen ...quelle
Es hört sich also so an, als ob das schlechte Commit irgendwann in ein Merge-Commit aufgenommen wurde. Wurde Ihr Merge-Commit bereits gezogen? Wenn ja, möchten Sie verwenden
git revert
; Sie müssen Ihre Zähne zusammenbeißen und die Konflikte bewältigen. Wenn nein, können Sie möglicherweise entweder neu gründen oder zurücksetzen, dies jedoch vor dem Festschreiben der Zusammenführung, und dann die Zusammenführung wiederholen.Es gibt nicht viel Hilfe, die wir Ihnen für den ersten Fall geben können. Nachdem Sie versucht haben, die Wiederherstellung durchzuführen, und festgestellt haben, dass die automatische Wiederherstellung fehlgeschlagen ist, müssen Sie die Konflikte untersuchen und entsprechend beheben. Dies ist genau der gleiche Vorgang wie das Beheben von Zusammenführungskonflikten. Sie können verwenden, um
git status
zu sehen, wo die Konflikte liegen, die nicht zusammengeführten Dateien bearbeiten, die in Konflikt stehenden Hunks finden, herausfinden, wie sie gelöst werden können, die in Konflikt stehenden Dateien hinzufügen und schließlich festschreiben. Wenn Siegit commit
selbst verwenden (nein-m <message>
), sollte die Nachricht, die in Ihrem Editor angezeigt wird, die Vorlagennachricht sein, die von erstellt wurdegit revert
. Sie können einen Hinweis hinzufügen, wie Sie die Konflikte behoben haben, und dann speichern und beenden, um ein Commit durchzuführen.Für den zweiten Fall, bei dem das Problem vor dem Zusammenführen behoben wurde, gibt es zwei Unterfälle, je nachdem, ob Sie seit dem Zusammenführen mehr Arbeit geleistet haben. Wenn Sie dies nicht
git reset --hard HEAD^
getan haben, können Sie die Zusammenführung einfach abbrechen, die Wiederherstellung durchführen und dann die Zusammenführung wiederholen. Aber ich vermute du hast. Am Ende machen Sie also so etwas:git rebase -i <something before the bad commit> <temporary branch>
, um das fehlerhafte Festschreiben zu entfernen).git rebase --onto <temporary branch> <old merge commit> <real branch>
quelle
Also haben Sie einige Arbeiten ausgeführt und sie vorangetrieben. Nennen wir sie Commits A und B. Ihr Mitarbeiter hat auch einige Arbeiten ausgeführt, C und D festgeschrieben. Auch (Commit F) und festgestellt, dass Ihr Mitarbeiter einige Dinge geändert hat, die er nicht haben sollte.
Ihr Commit-Verlauf sieht also folgendermaßen aus:
Sie wollen wirklich C, D und D 'loswerden. Da Sie sagen, dass Sie die Arbeit Ihrer Mitarbeiter in Ihre Arbeit integriert haben, sind diese Commits bereits "da draußen". Das Entfernen der Commits mithilfe von z. B. git rebase ist also ein Nein-Nein. Glauben Sie mir, ich habe es versucht.
Jetzt sehe ich zwei Auswege:
Wenn Sie E und F noch nicht an Ihren Kollegen oder an eine andere Person (normalerweise Ihren "Ursprungs" -Server) gesendet haben, können Sie diese vorerst noch aus dem Verlauf entfernen. Dies ist Ihre Arbeit, die Sie speichern möchten. Dies kann mit einem erfolgen
(Ersetzen Sie D 'durch den tatsächlichen Commit-Hash, den Sie von a erhalten können
git log
Zu diesem Zeitpunkt sind die Commits E und F weg und die Änderungen sind wieder nicht festgeschriebene Änderungen in Ihrem lokalen Arbeitsbereich. An diesem Punkt würde ich sie in einen Zweig verschieben oder in einen Patch verwandeln und für später speichern. Setzen Sie jetzt die Arbeit Ihres Kollegen entweder automatisch mit
git revert
oder manuell zurück. Wenn Sie das getan haben, spielen Sie Ihre Arbeit noch einmal ab. Möglicherweise haben Sie Zusammenführungskonflikte, aber zumindest befinden sie sich in dem Code, den Sie geschrieben haben, anstelle des Codes Ihres Kollegen.Wenn Sie die Arbeit, die Sie nach den Commits Ihres Kollegen geleistet haben, bereits vorangetrieben haben, können Sie trotzdem versuchen, entweder manuell oder mithilfe eines "Reverse Patch" zu erhalten
git revert
, aber da Ihre Arbeit sozusagen "im Weg" ist, werden Sie wahrscheinlich so etwas bekommen mehr Zusammenführungskonflikte und verwirrendere. Sieht so aus, als wären Sie dort gelandet ...quelle
git revert --strategy Auflösung, wenn Commit eine Zusammenführung ist: Verwenden Sie git revert --strategy Auflösung -m 1
quelle