1812 Stimmen

Wie kann ich in Git selektiv Änderungen aus einem anderen Zweig zusammenführen oder auswählen?

Ich verwende Git für ein neues Projekt, das zwei parallele - aber derzeit experimentelle - Entwicklungszweige hat:

  • master Import der bestehenden Codebasis plus einige Änderungen, bei denen ich mir im Allgemeinen sicher bin
  • exp1 : Versuchszweig #1
  • exp2 : Versuchszweig #2

exp1 y exp2 stehen für zwei sehr unterschiedliche Architekturansätze. Solange ich nicht weitergekommen bin, kann ich nicht wissen, welcher Ansatz (wenn überhaupt) funktionieren wird. Wenn ich in einem Zweig Fortschritte mache, habe ich manchmal Bearbeitungen, die im anderen Zweig nützlich wären, und möchte genau diese zusammenführen.

Was ist der beste Weg, um selektive Änderungen von einem Entwicklungszweig in einen anderen zusammenzuführen und dabei alles andere zurückzulassen?

Ansätze, die ich in Betracht gezogen habe:

  1. git merge --no-commit gefolgt von der manuellen Freigabe einer großen Anzahl von Bearbeitungen, die ich nicht zwischen den Zweigen austauschen möchte.

  2. Manuelles Kopieren von gemeinsamen Dateien in ein temporäres Verzeichnis, gefolgt von git checkout um in den anderen Zweig zu wechseln und dann mehr manuelles Kopieren aus dem temporären Verzeichnis in den Arbeitsbaum.

  3. Eine Abwandlung des obigen Beispiels. Verzichten Sie auf die exp Zweigen und verwenden Sie zwei zusätzliche lokale Repositories für Experimente. Dies macht das manuelle Kopieren von Dateien viel einfacher.

Alle drei Ansätze erscheinen mühsam und fehleranfällig. Ich hoffe, dass es einen besseren Ansatz gibt; so etwas wie einen Filterpfad-Parameter, der die git-merge wählerischer.

69voto

Eric Hu Punkte 17730

Während einige dieser Antworten ziemlich gut sind, habe ich das Gefühl, dass keine davon die ursprüngliche Bedingung des Auftraggebers erfüllt: die Auswahl bestimmter Dateien aus bestimmten Zweigen. Diese Lösung macht das, aber es kann mühsam sein, wenn es viele Dateien gibt.

Nehmen wir an, Sie haben die master , exp1 y exp2 Zweige. Sie möchten eine Datei aus jedem der experimentellen Zweige in den Master-Zweig einbinden. Ich würde etwa so vorgehen:

git checkout master
git checkout exp1 path/to/file_a
git checkout exp2 path/to/file_b

# Save these files as a stash
git stash

# Merge stash with master
git merge stash

Dadurch erhalten Sie In-File-Diffs für jede der gewünschten Dateien. Nicht mehr. Nicht mehr und nicht weniger. Es ist nützlich, wenn Sie radikal unterschiedliche Datei-Änderungen zwischen Versionen haben - in meinem Fall die Änderung einer Anwendung von Ruby on Rails 2 zu Ruby on Rails 3.

Damit werden Dateien zusammengeführt, aber auf intelligente Weise. Ich konnte nicht herausfinden, wie man mit dieser Methode Informationen über die Unterschiede in der Datei erhält (vielleicht ist das bei extremen Unterschieden noch möglich). Lästige Kleinigkeiten wie Leerzeichen werden wieder eingefügt, es sei denn, Sie verwenden die -s recursive -X ignore-all-space Option)

57voto

Cory Punkte 20338

Die Antwort von 1800 INFORMATION ist völlig korrekt. Als jemand, der neu in Git ist, war "use git cherry-pick" jedoch nicht genug für mich, um dies herauszufinden, ohne ein bisschen mehr im Internet zu suchen, also dachte ich, ich würde eine detailliertere Anleitung posten, falls jemand in einem ähnlichen Boot sitzt.

Mein Anwendungsfall war, dass ich selektiv Änderungen aus dem GitHub-Zweig einer anderen Person in meinen eigenen ziehen wollte. Wenn Sie bereits einen lokalen Zweig mit den Änderungen haben, müssen Sie nur die Schritte 2 und 5-7 ausführen.

  1. Erstellen Sie (falls noch nicht geschehen) einen lokalen Zweig mit den Änderungen, die Sie einbringen möchten.

    $ git branch mybranch <base branch>

  2. Schalten Sie es ein.

    $ git checkout mybranch

  3. Ziehen Sie die gewünschten Änderungen aus dem Konto der anderen Person herunter. Wenn Sie das noch nicht getan haben, sollten Sie sie als entfernte Person hinzufügen.

    $ git remote add repos-w-changes <git url>

  4. Reißen Sie alles von ihrem Ast herunter.

    $ git pull repos-w-changes branch-i-want

  5. Sehen Sie sich die Übergabeprotokolle an, um zu sehen, welche Änderungen Sie wünschen:

    $ git log

  6. Wechseln Sie zurück zu dem Zweig, in den Sie die Änderungen ziehen wollen.

    $ git checkout originalbranch

  7. Wählen Sie Ihre Übertragungen einzeln mit den Hashes aus.

    $ git cherry-pick -x hash-of-commit

46voto

maestr0 Punkte 4918

So können Sie ersetzen Myclass.java Datei in master Zweig mit Myclass.java en feature1 Zweigstelle. Es funktioniert auch, wenn Myclass.java existiert nicht auf master .

git checkout master
git checkout feature1 Myclass.java

Beachten Sie, dass dadurch lokale Änderungen im Masterzweig überschrieben - nicht zusammengeführt - und ignoriert werden.

32voto

masukomi Punkte 9245

Der einfache Weg, um tatsächlich zusammenführen bestimmte Dateien aus zwei Zweigen, nicht nur bestimmte Dateien durch solche aus einem anderen Zweig ersetzen.

Schritt eins: Diffusion der Zweige

git diff branch_b > my_patch_file.patch

Erzeugt eine Patchdatei mit dem Unterschied zwischen dem aktuellen Zweig und Zweig_b

Zweiter Schritt: Anwenden des Patches auf Dateien, die einem Muster entsprechen

git apply -p1 --include=pattern/matching/the/path/to/file/or/folder my_patch_file.patch

Nützliche Hinweise zu den Optionen

Sie können verwenden * als Platzhalter im Include-Muster.

Schrägstriche müssen nicht ausgeklammert werden.

Sie könnten stattdessen auch --exclude verwenden und den Patch auf alle Dateien anwenden, die nicht dem Muster entsprechen, oder den Patch mit -R umkehren

Die Option -p1 ist ein Überbleibsel des *Unix-Patch-Befehls und der Tatsache, dass der Inhalt der Patch-Datei jedem Dateinamen den Zusatz a/ o b/ (oder mehr, je nachdem, wie die Patchdatei erzeugt wurde), die Sie entfernen müssen, damit es die echte Datei mit dem Pfad zu der Datei, auf die der Patch angewendet werden muss, vergleichen kann.

Weitere Optionen finden Sie in der Manpage für git-apply.

Dritter Schritt: Es gibt keinen dritten Schritt

Natürlich möchten Sie Ihre Änderungen festschreiben, aber wer kann schon sagen, dass Sie nicht noch andere Änderungen vornehmen möchten, bevor Sie die Änderungen festschreiben.

25voto

jejese Punkte 111

Hier sehen Sie, wie Sie die Historie dazu bringen können, nur ein paar Dateien aus einem anderen Zweig mit einem Minimum an Aufwand zu übernehmen, auch wenn ein "einfacher" Merge viel mehr Änderungen mit sich gebracht hätte, die Sie nicht wollen.

Zunächst gehen Sie den ungewöhnlichen Schritt, im Voraus zu erklären, dass es sich bei dem, was Sie übertragen wollen, um eine Zusammenführung handelt, ohne dass Git irgendetwas mit den Dateien in Ihrem Arbeitsverzeichnis macht:

git merge --no-ff --no-commit -s ours branchname1

... wobei "branchname" das ist, von dem Sie behaupten, dass Sie es zusammenführen wollen. Wenn Sie sofort eine Übergabe durchführen, werden keine Änderungen vorgenommen, aber es wird immer noch die Abstammung von dem anderen Zweig angezeigt. Sie können auch weitere Zweige, Tags usw. in der Befehlszeile hinzufügen, wenn Sie dies wünschen. Zu diesem Zeitpunkt gibt es jedoch keine Änderungen zu übertragen, also holen Sie sich als nächstes die Dateien aus den anderen Revisionen.

git checkout branchname1 -- file1 file2 etc.

Wenn Sie von mehr als einem anderen Zweig zusammengeführt haben, wiederholen Sie dies nach Bedarf.

git checkout branchname2 -- file3 file4 etc.

Jetzt befinden sich die Dateien aus dem anderen Zweig im Index, bereit für die Übergabe, mit Historie.

git commit

Und Sie werden in dieser Commit-Nachricht eine Menge zu erklären haben.

Bitte beachten Sie jedoch, falls es noch nicht klar war, dass dies eine sehr unschöne Sache ist. Es entspricht nicht dem Sinn einer "Verzweigung", und "Rosinenpicken" ist ein ehrlicherer Weg, um das zu tun, was Sie hier tun würden. Wenn Sie einen weiteren "Merge" für andere Dateien auf demselben Zweig machen wollen, die Sie beim letzten Mal nicht übernommen haben, wird er Sie mit der Meldung "already up to date" stoppen. Das ist ein Symptom dafür, dass wir nicht verzweigt haben, wenn wir es hätten tun sollen, da der "von"-Zweig mehr als ein anderer Zweig sein sollte.

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