Ich muss ein "mittleres" Commit in meiner Hauptniederlassung anzeigen und wegwerfen. Wie kann ich es tun?

94

Zum Beispiel muss ich im folgenden Hauptzweig nur das Commit af5c7bf16e6f04321f966b4231371b21475bc4da in den Papierkorb werfen, das das zweite aufgrund der vorherigen Rebase ist:

commit 60b413512e616997c8b929012cf9ca56bf5c9113
Author: Luca G. Soave <[email protected]>
Date:   Tue Apr 12 23:50:15 2011 +0200

    add generic config/initializers/omniauth.example.rb

commit af5c7bf16e6f04321f966b4231371b21475bc4da
Author: Luca G. Soave <[email protected]>
Date:   Fri Apr 22 00:15:50 2011 +0200

    show github user info if logged

commit e6523efada4d75084e81971c4dc2aec621d45530
Author: Luca G. Soave <[email protected]>
Date:   Fri Apr 22 17:20:48 2011 +0200

    add multiple .container at blueprint layout

commit 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22
Author: Luca G. Soave <[email protected]>
Date:   Thu Apr 21 19:55:57 2011 +0200

    add %h1 Fantastic Logo + .right for 'Sign in with Github'

Ich muss Mantain

  • das erste Commit 60b413512e616997c8b929012cf9ca56bf5c9113,
  • das dritte Commit e6523efada4d75084e81971c4dc2aec621d45530 und
  • das letzte Commit 414ceffc40ea4ac36ca68e6dd0a9ee97e73dee22

"wegwerfen" nur das zweite Commit af5c7bf16e6f04321f966b4231371b21475bc4da

Wie kann ich das machen? Danke im Voraus, Luca

Luca G. Soave
quelle

Antworten:

98

Rebase oder revert sind die Optionen. Rebase entfernt das Commit tatsächlich aus dem Verlauf, sodass es so aussieht, als ob das zweite Commit nie existiert hätte. Dies ist ein Problem, wenn Sie den Hauptzweig auf andere Repos verschoben haben. Wenn Sie in diesem Fall versuchen, nach einer Rebase zu pushen, gibt git einen Fehler beim Zusammenführen von nicht schnell vorlaufenden Zusammenführungen aus .

Zurücksetzen ist die richtige Lösung, wenn der Zweig mit anderen Repos geteilt wurde. git revert af5c7bf16wird ein neues Commit durchführen, das einfach die von af5c7bf16 eingeführten Änderungen rückgängig macht. Auf diese Weise wird der Verlauf nicht neu geschrieben, Sie führen eine klare Aufzeichnung des Fehlers und andere Repos akzeptieren den Push.

Hier ist eine gute Möglichkeit zum Löschen: Damit gelangen git rebase -i <commit>^ Sie zum Commit kurz vor dem Commit, das Sie entfernen möchten. Der interaktive Editor zeigt Ihnen eine Liste aller Commits bis zu diesem Punkt. Sie können auswählen, quetschen usw. In diesem Fall entfernen Sie die Zeile für das Commit, das Sie löschen und die Datei speichern möchten. Rebase wird seine Arbeit beenden.

JCotton
quelle
2
Wenn ich mich für Rebase entscheide, was ist das richtige Commit für Rebase? Ich muss nur die Sekunde fallen lassen ...
Luca G. Soave
@ BBJ3 Siehe Mipadis Antwort.
Prajwal Dhatwalia
32

Wenn Rebase eine Option ist, können Sie Rebase erstellen und einfach löschen:

$ git rebase -i 414ceffc^

Wenn Rebase keine Option ist, können Sie sie einfach zurücksetzen:

$ git revert af5c7bf16
Mipadi
quelle
Wenn ich für "git rebase 414ceffc" das ältere vierte Commit habe, werde ich dann nicht auch das dritte e6523 und das erste 60b41 verlieren?
Luca G. Soave
3
@Luca G. Soave: Sie "verlieren" ein Commit nur, wenn Sie ausdrücklich anweisen, es zu löschen git rebase(indem Sie es rebaseim interaktiven Modus ausführen und seinen Eintrag entfernen).
Mipadi
Danke Mipadi, ich gebe JCotton meine Stimme im Wesentlichen für die ausführliche Erklärung, auch wenn ihr zwei dasselbe gesagt habt ... nochmals vielen Dank.
Luca G. Soave
29

Trotz aller Anerkennung, die die ursprünglichen Antworten hier erhalten haben, fand ich sie nicht ganz zufriedenstellend, um die Frage zu beantworten. Wenn Sie sich in einer Situation befinden, in der Sie ein Commit oder eine Sammlung von Commits aus der Mitte des Verlaufs entfernen müssen, schlage ich Folgendes vor:

  • Erstellen Sie einen neuen Zweig am Kopf desjenigen, der alle Commits enthält, und wechseln Sie zu diesem.
  • Setzen Sie den neuen Zweig auf den Punkt zurück, an dem Sie eine neue Basis starten möchten.
  • Dann (hier ist der entscheidende Punkt) Kirsche holen die nachfolgenden Commits wollen Sie eigentlich danach auf die neue von der ursprünglichen Zweig angewendet werden, und überspringen die Commits Sie will nicht mehr (dh diejenigen , die Sie löschen).
  • Wenn gewünscht, benennen Sie den ursprünglichen Zweig in etwas um, das den alten Code anzeigt, und benennen Sie dann Ihren neuen Zweig um, wie der ursprüngliche genannt wurde.
  • Übertragen Sie Ihre Änderungen schließlich auf Ihr Remote-Repo (falls Sie eines verwenden). Sie müssen wahrscheinlich einen "erzwungenen Stoß" verwenden. Wenn Ihre Mitarbeiter Probleme beim Abrufen der Revisionen haben, ist es für sie möglicherweise am einfachsten, das Repo erneut von der Remote-Quelle zu klonen. Auf die eine oder andere Weise möchten Sie wahrscheinlich mit ihnen sprechen, wenn Sie ohnehin Commits aus der Mitte Ihrer Geschichte herausreißen!

Hier sind Informationen zum Cherry Picking: Was bedeutet das Cherry Picking eines Commits mit Git?

Hier sind einige Beispiele für Tortoise Git (wie ich es gerade getan habe). Es ist definitiv einfacher, ein GUI-Dienstprogramm für diese Art von Operationen zu verwenden! Kirschpickel mit TortoiseGit

BuvinJ
quelle
6
Dies sollte die beste Antwort gewesen sein!
MadOgre
Diese Lösung ist eine gute Möglichkeit, Cherry Pick zu verwenden. Sie ist sogar noch besser, wenn Sie mehr als ein Commit "überspringen" möchten.
Johnny Willer
Die ursprüngliche Frage nicht wirklich ansprechen. Während die vorgeschlagene Lösung funktioniert, ist sie viel zeitaufwändiger / umständlicher und IMO bringt keinen Nutzen. Wenn der Zweig bereits gepusht wurde (und in freier Wildbahn verwendet wird), ist die Rücksetzstrategie wahrscheinlich die Antwort. Wenn nicht, würde ich Interactive neu starten und das beleidigende Commit entfernen. Wenn es gedrückt wurde, aber wir wissen, dass es von niemandem verwendet wird, können Sie trotzdem mit einer Rebase, gefolgt von einem Force Push, davonkommen.
Raduw