492 Stimmen

Bestimmte Übertragung entfernen

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 mit meiner verschmolzen, entweder, als ich sie abgerufen habe, oder als ich versucht habe, nur die Dateien herauszusuchen, die ich wollte. Ich habe lange gesucht und herumgespielt, um herauszufinden, wie man die Commits entfernt, die die Änderungen an diesen Dateien enthalten, es scheint eine Entscheidung zwischen revert und rebase zu sein, und es gibt keine eindeutigen Beispiele, und die Dokumentation geht davon aus, dass ich mehr weiß als ich tue.

Hier ist also eine vereinfachte Version der Frage:

Wie entferne ich in dem folgenden Szenario die Übergabe 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, umzukehren

$ 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.

24voto

Dennis Punkte 51330

Sie können unerwünschte Übertragungen mit git rebase . Angenommen, Sie nehmen einige Commits aus dem Themenzweig eines Kollegen in Ihren Themenzweig auf, entscheiden aber später, dass Sie diese Commits nicht haben wollen.

git checkout -b tmp-branch my-topic-branch  # Use a temporary branch to be safe.
git rebase -i master  # Interactively rebase against master branch.

An dieser Stelle öffnet Ihr Texteditor die interaktive Rebase-Ansicht. Zum Beispiel

git-rebase-todo

  1. Entfernen Sie die Commits, die Sie nicht wollen, indem Sie die entsprechenden Zeilen löschen
  2. Speichern und Beenden

Wenn die Umbasierung nicht erfolgreich war, löschen Sie den temporären Zweig und versuchen Sie eine andere Strategie. Ansonsten fahren Sie mit den folgenden Anweisungen fort.

git checkout my-topic-branch
git reset --hard tmp-branch  # Overwrite your topic branch with the temp branch.
git branch -d tmp-branch  # Delete the temporary branch.

Wenn Sie Ihren Themenzweig an einen entfernten Ort verschieben, müssen Sie möglicherweise einen Push erzwingen, da sich der Commit-Verlauf geändert hat. Wenn andere an demselben Zweig arbeiten, sollten Sie sie vorwarnen.

12voto

sdaau Punkte 34279

Nach den anderen Antworten hier war ich etwas verwirrt darüber, wie git rebase -i verwendet werden, um einen Commit zu entfernen. Ich hoffe, es ist in Ordnung, wenn ich hier meinen Testfall aufschreibe (der dem des OP sehr ähnlich ist).

Hier ist ein bash Skript, das Sie einfügen können, um ein Test-Repository in der /tmp Ordner:

set -x

rm -rf /tmp/myrepo*
cd /tmp

mkdir myrepo_git
cd myrepo_git
git init
git config user.name me
git config user.email me@myself.com

mkdir folder
echo aaaa >> folder/file.txt
git add folder/file.txt
git commit -m "1st git commit"

echo bbbb >> folder/file.txt
git add folder/file.txt
git commit -m "2nd git commit"

echo cccc >> folder/file.txt
git add folder/file.txt
git commit -m "3rd git commit"

echo dddd >> folder/file.txt
git add folder/file.txt
git commit -m "4th git commit"

echo eeee >> folder/file.txt
git add folder/file.txt
git commit -m "5th git commit"

An diesem Punkt haben wir eine file.txt mit diesen Inhalten:

aaaa
bbbb
cccc
dddd
eeee

Zu diesem Zeitpunkt ist HEAD beim 5. Commit, HEAD~1 wäre der 4. und HEAD~4 wäre der 1. Commit (HEAD~5 würde also nicht existieren). Sagen wir, wir wollen den 3. Commit entfernen - wir können diesen Befehl in der myrepo_git Verzeichnis:

git rebase -i HEAD~4

( Beachten Sie, dass git rebase -i HEAD~5 ergibt "fatal: Benötigte eine einzelne Revision; ungültiger Upstream HEAD~5". ) Ein Texteditor (siehe Screenshot in @Dennis' Antwort ) wird mit diesem Inhalt geöffnet:

pick 5978582 2nd git commit
pick 448c212 3rd git commit
pick b50213c 4th git commit
pick a9c8fa1 5th git commit

# Rebase b916e7f..a9c8fa1 onto b916e7f
# ...

Wir erhalten also alle Übertragungen seit (aber ohne ) unser gewünschtes HEAD~4. Löschen Sie die Zeile pick 448c212 3rd git commit und speichern Sie die Datei; Sie erhalten dann folgende Antwort von git rebase :

error: could not apply b50213c... 4th git commit

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To check out the original branch and stop rebasing run "git rebase --abort".
Could not apply b50213c... 4th git commit

Öffnen Sie an dieser Stelle myrepo_git/ folder/file.txt in einem Texteditor; Sie werden sehen, dass sie geändert wurde:

aaaa
bbbb
<<<<<<< HEAD
=======
cccc
dddd
>>>>>>> b50213c... 4th git commit

Im Grunde genommen, git sieht, dass, als HEAD zur 2. Übergabe kam, es Inhalt von aaaa + bbbb ; und dann hat es einen Fleck mit zusätzlichen cccc + dddd die es nicht an den vorhandenen Inhalt anhängen kann.

Also hier git kann nicht für Sie entscheiden - es ist Sie der eine Entscheidung treffen muss: Wenn Sie die 3. Übergabe entfernen, behalten Sie entweder die durch sie eingeführten Änderungen (hier die Zeile cccc ) - oder eben nicht. Wenn nicht, entfernen Sie einfach die zusätzlichen Zeilen - einschließlich der cccc - in folder/file.txt mit einem Texteditor, so dass es wie folgt aussieht:

aaaa
bbbb
dddd

... und dann speichern folder/file.txt . Jetzt können Sie die folgenden Befehle in myrepo_git Verzeichnis:

$ nano folder/file.txt  # text editor - edit, save
$ git rebase --continue
folder/file.txt: needs merge
You must edit all merge conflicts and then
mark them as resolved using git add

Ah - um also zu markieren, dass wir den Konflikt gelöst haben, müssen wir muss git add die folder/file.txt , bevor sie git rebase --continue :

$ git add folder/file.txt
$ git rebase --continue

Hier öffnet sich wieder ein Texteditor und zeigt die Zeile 4th git commit - hier haben wir die Möglichkeit, die Commit-Nachricht zu ändern (die in diesem Fall sinnvollerweise in 4th (and removed 3rd) commit oder ähnlich). Angenommen, Sie wollen das nicht - dann beenden Sie einfach den Texteditor, ohne zu speichern; sobald Sie das tun, erhalten Sie:

$ git rebase --continue
[detached HEAD b8275fc] 4th git commit
 1 file changed, 1 insertion(+)
Successfully rebased and updated refs/heads/master.

An diesem Punkt haben Sie nun einen Verlauf wie diesen (den Sie auch mit z.B. gitk . oder andere Tools) der Inhalte von folder/file.txt (mit offenbar unveränderten Zeitstempeln der ursprünglichen Übertragungen):

1st git commit  |  +aaaa
----------------------------------------------
2nd git commit  |   aaaa
                |  +bbbb
----------------------------------------------
4th git commit  |   aaaa
                |   bbbb
                |  +dddd
----------------------------------------------
5th git commit  |   aaaa
                |   bbbb
                |   dddd
                |  +eeee

Und wenn wir vorher beschlossen haben, die Linie beizubehalten cccc (der Inhalt des 3. Git-Commits, den wir entfernt haben), hätten wir das:

1st git commit  |  +aaaa
----------------------------------------------
2nd git commit  |   aaaa
                |  +bbbb
----------------------------------------------
4th git commit  |   aaaa
                |   bbbb
                |  +cccc
                |  +dddd
----------------------------------------------
5th git commit  |   aaaa
                |   bbbb
                |   cccc
                |   dddd
                |  +eeee

Nun, das war die Art von Lektüre, die ich zu finden gehofft hatte, um zu verstehen, wie git rebase funktioniert in Bezug auf das Löschen von Commits/Revisionen; ich hoffe, es hilft auch anderen...

4voto

Cascabel Punkte 449595

Es klingt also so, als ob der schlechte Commit irgendwann in einen Merge-Commit integriert wurde. Wurde Ihr Merge-Commit schon gezogen? Wenn ja, dann sollten Sie git revert dann müssen Sie die Zähne zusammenbeißen und die Konflikte aushalten. Wenn nein, dann könnten Sie entweder rebase oder revert, aber Sie können dies tun vor die Zusammenführungsübergabe und führen Sie die Zusammenführung erneut durch.

Für den ersten Fall können wir Ihnen nicht viel helfen, wirklich. Nachdem Sie die Rückgängigmachung versucht und festgestellt haben, dass die automatische Rückgängigmachung fehlgeschlagen ist, müssen Sie die Konflikte untersuchen und sie entsprechend beheben. Dies ist genau derselbe Prozess wie das Beheben von Konflikten beim Zusammenführen; Sie können git status um zu sehen, wo die Konflikte sind, die nicht zusammengefassten Dateien zu bearbeiten, die konfliktbehafteten Hunks zu finden, herauszufinden, wie man sie auflöst, die konfliktbehafteten Dateien hinzuzufügen und schließlich zu übertragen. Wenn Sie git commit selbst (keine -m <message> ), sollte die Nachricht, die in Ihrem Editor erscheint, die Vorlagennachricht sein, die von git revert Sie können eine Notiz hinzufügen, wie Sie die Konflikte behoben haben, und dann speichern und beenden, um den Vorgang zu bestätigen.

Im zweiten Fall wird das Problem behoben vor Ihrer Zusammenführung gibt es zwei Unterfälle, je nachdem, ob Sie seit der Zusammenführung weitere Arbeiten durchgeführt haben. Wenn dies nicht der Fall ist, können Sie einfach git reset --hard HEAD^ um die Zusammenführung aufzuheben, die Rückgängigmachung durchzuführen und dann die Zusammenführung erneut durchzuführen. Aber ich nehme an, dass Sie das getan haben. Also werden Sie am Ende so etwas wie dies tun:

  • einen temporären Zweig kurz vor der Zusammenführung erstellen und diesen auschecken
  • den Revert durchführen (oder mit git rebase -i <something before the bad commit> <temporary branch> um die fehlerhafte Übertragung zu entfernen)
  • die Zusammenführung wiederholen
  • Ihre spätere Arbeit wieder darauf aufbauen: git rebase --onto <temporary branch> <old merge commit> <real branch>
  • den temporären Zweig entfernen

2voto

ShaDow RiDeR Punkte 61

Git revert --strategy resolve wenn die Übergabe eine Zusammenführung ist: git revert --strategy resolve -m 1 verwenden

2voto

Mclamee Punkte 21

Ich habe eine einfache Lösung mit einem Patch, der alle Ihre Änderungen rückgängig macht.

  1. Auschecken des aktuellen Hauptzweigs (z. B. develop)

    git checkout develop

  2. Schauen Sie sich Ihre Commit-ID im Verlaufsprotokoll an, und checken Sie nur Ihre Änderungen in einen neuen Zweig aus:

    git log git checkout -b your-branch <your-commit-id>

  3. Schauen Sie in Ihrer Verzweigung nach und suchen Sie den vorherigen Status, zu dem Sie zurückkehren möchten:

    git checkout -b prev-status <previous-commit-id>

  4. Erstellen Sie einen Patch, der alle Ihre Änderungen rückgängig machen kann:

    git diff your-branch..prev-status > reverts.patch

    the comparing order of branches is important

  5. den aktuellen Hauptzweig auschecken und den Reverting-Patch anwenden

    git checkout origin develop git apply reverts.patch git add * git commit -m "revert all my changes"

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X