Wie kann ich mit GIT Änderungen von einem Commit auf einem anderen 'Fork' selektiv zusammenführen?

81

Nehmen Sie dieses Szenario:

  1. Ich beschließe, eine Codebasis auf github.com zu "gabeln" und meine Routine auszuführen: Bearbeiten - Festschreiben - Push; aka Hack Hack Hack.
  2. Nachdem ich einige Änderungen vorgenommen habe, sehe ich einige Änderungen, die eine andere Person am selben Projekt vorgenommen hat, und ich mag sie!
  3. Ich beschließe, sie in meine zusammenzuführen. Das Problem ist, ich möchte nur einen Teil eines bestimmten Commits von mehreren Commits, die er gemacht hat.

Was wäre die effizienteste Methode, um diese ausgewählte Anzahl von Änderungen in meine 'Gabel' zu integrieren?

Tim
quelle

Antworten:

119

Nachdem jemand die Wellen der IRC-Welt durchforstet hatte, gab er eine großartige Lösung:

git cherry-pick SHA1 --no-commit
git add --patch

Hoffentlich hilft das allen anderen bei der gleichen Frage!

EDIT: OK, vielleicht ist es nicht ganz so einfach. Hier sind die vollständigen Schritte:

  1. Zuerst müssen Sie sich in Ihrem Repository befinden und die erforderlichen cdSchritte ausführen, um zu Ihrem Arbeitsverzeichnis zu gelangen.

  2. Sie müssen jetzt den Remote-Zweig hinzufügen und dann abrufen. Tun Sie dies durch:

    git remote add someUser git://github.com/someUser/someRepo.git

    git fetch someUser

  3. Sie können jetzt Befehle ausführen git log someUser/master, um beispielsweise den Commit-SHA1 zu finden, den Sie "teilweise" zusammenführen möchten.

  4. Sobald Sie die SHA haben, können Sie jetzt ausführen:

    git cherry-pick -n SHA1

    Wo SHA1ist das Commit SHA, duh!

  5. Es kann durchaus zu Konflikten kommen, je nachdem, wie alt das Commit ist und wie oft sich dieser bestimmte Bereich des Projekts ändert. Entschuldigung, aber Sie müssen diese manuell mit Ihrem vertrauenswürdigen Editor beheben. Ziehen Sie also VIM oder was auch immer Sie verwenden heraus und hacken Sie die Konflikte ab, bis Sie das Stadium erreicht haben, in dem Ihnen die Änderungen gefallen.

  6. Sie müssen jetzt den Index auf die HEAD-Revision zurücksetzen und können dann mit dem vertrauenswürdigen GIT- add --patchBefehl auswählen, welche Änderungen Sie wünschen:

    git reset HEAD

    git add --patch oder git add -p

  7. Yay! Festschreibungszeit:

    git commit -m "I merged a select amount of changes"

  8. git add --patchFühren Sie Folgendes aus, um das Chaos zu beseitigen (das Zeug, zu dem Sie Nein gesagt haben ) und nur die ausgewählten Änderungen in Ihrem Arbeits-Repository beizubehalten:

    git reset --hard HEAD

    Anscheinend git checkout -fist auch eine andere Option.

Tim
quelle
Ich bin froh, dass du gefunden hast git add -p. es ist extrem mächtig. Wenn Sie das betreffende Commit bereits haben (z. B. nicht --no-commitfür den Cherry-Pick verwendet, oder es ist eines Ihrer Commits), können Sie git reset HEAD^den Index eines Commits zurückspulen und dann die Änderungen git add -pin Schritten wieder hinzufügen . Wenn sich das Commit nicht an der Verzweigungsspitze befindet, können Sie git rebase -idas betreffende Commit verwenden und bearbeiten.
Cascabel
3
schöner Durchgang. Denken Sie daran, wenn Sie nur das gesamte Commit möchten , geben Sie einfach das -nin Schritt 4 aus. So:git cherry-pick SHA1
Hulvej
Das Schlüsselbit hier ist git remote add <user> <fork-url>- dann können Sie git cherry-pickwie gewohnt.
Tom
2

Mir ist nicht klar, was Sie wollen. Wenn Sie nur bestimmte Commits von den anderen Gabeln einbringen möchten, können Sie verwenden git cherry-pick SHA. Vollständige Erklärung zu gitready .

hgmnz
quelle
Ich bin erst nach einem 'Teil' / 'Abschnitt' / 'ein paar Zeilen' eines bestimmten Commits in meinem Repository zusammengeführt. Nicht besonders dateispezifisch.
Tim
In diesem Fall ist Git Format-Patch SHA, Git
Apply
2

Ich mag Tims Lösung sehr, aber manchmal bastele ich gerne in vimdiff. Meine Lösung für dieses Problem ist grob, aber es funktioniert für mich, weil ich vim mag.

Ich habe vimdiff als mein Difftool festgelegt, und um dann selektiv zusammenzuführen, differenziere ich den Zweig:

git difftool <branch> <file>

Dann gehe ich in den Bereich mit der Version des aktuellen Zweigs und bearbeite das Original in vim (manchmal ist dies nicht erforderlich, aber manchmal öffnet vimdiff eine Version in / tmp) und deaktiviere den schreibgeschützten Modus:

:e <file>
:set readonly!

Jetzt kann ich die Patch-Tools von vim wie dound verwenden dp, um das anzuwenden, was ich möchte, und andere kleine Änderungen vornehmen, während ich gehe. Wenn ich fertig bin, speichere ich die Datei, beende vim und stelle die Datei in git wie eine reguläre Bearbeitung bereit.

Wie gesagt, das ist nicht besonders ausgefeilt, aber es ist sehr mächtig und immer noch rein in der Kommandozeile. Stellen Sie nur sicher, dass Sie eine eindeutige Festschreibungsnachricht hinzufügen, da git nicht automatisch eine Zusammenführungsnachricht für Sie enthält.

vimdiff Beispiel http://j.mp/1dZVllt

Mike Dacre
quelle
Ich denke nicht, dass diese Antwort als eine unabhängige, vollwertige Antwort würdig ist. Nützliche Informationen, aber nicht besonders relevant. (Warum steht das ganz oben auf den Antworten?)
Mike Kormendy
1

Wenn Sie nur einen Port für ein Commit möchten, ist es wahrscheinlich am besten, wenn Sie das gewünschte Commit auswählen und Dateien zurücksetzen, die nicht berührt werden sollen.

git cherry-pick SHA1
git checkout HEAD file1 file2 ... fileN

Wenn Sie mehrere geänderte Teile in einer Datei haben und nur einige davon behalten möchten, haben Sie natürlich keine andere Wahl, als die Datei manuell zu bearbeiten und deren Änderungen auszuschneiden.

Bombe
quelle
2
Ist die Kasse hier notwendig? Setzt der Befehl cherry pick die Änderungen nicht in Ihr Arbeitsverzeichnis?
Casey Watson