Ich verwende Git für ein neues Projekt, das zwei parallele - aber derzeit experimentelle - Entwicklungszweige hat:
master
: Import der bestehenden Codebasis plus ein paar Modifikationen, bei denen ich mir generell sicher binexp1
: experimenteller Zweig #1exp2
: experimenteller Zweig #2exp1
und exp2
stellen zwei sehr unterschiedliche Architekturansätze dar. Solange ich nicht weiter bin, kann ich nicht wissen, welcher davon (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:
git merge --no-commit
gefolgt von manuellem Unstaging einer großen Anzahl von Änderungen, die ich nicht zwischen den Zweigen gemeinsam machen möchte.Manuelles Kopieren gemeinsamer Dateien in ein temporäres Verzeichnis, gefolgt von git checkout
, um in den anderen Zweig zu wechseln, und dann weiteres manuelles Kopieren aus dem temporären Verzeichnis in den Arbeitsbaum.
Eine Abwandlung des oben genannten. Verzichten Sie vorerst auf die exp
-Zweige und verwenden Sie zwei zusätzliche lokale Repositories für Experimente. Dies macht das manuelle Kopieren von Dateien sehr viel einfacher.
Alle drei Ansätze scheinen mühsam und fehleranfällig zu sein. Ich hoffe, dass es einen besseren Ansatz gibt; so etwas wie einen Filterpfad-Parameter, der git-merge
selektiver machen würde.
Sie verwenden den Befehl cherry-pick, um einzelne Übertragungen aus einem Zweig zu erhalten.
Wenn die gewünschte(n) Änderung(en) nicht in einzelnen Commits enthalten ist/sind, dann verwenden Sie die hier gezeigte Methode, um den Commit in einzelne Commits aufzuteilen. Grob gesagt, benutzen Sie git rebase -i
, um den ursprünglichen Commit zu bearbeiten, dann git reset HEAD^
, um selektiv Änderungen rückgängig zu machen, und dann git commit
, um diesen Teil als neuen Commit in die History zu schreiben.
Es gibt eine weitere nette Methode hier im Red Hat Magazine, wo sie git add --patch
oder möglicherweise git add --interactive
benutzen, was Ihnen erlaubt, nur Teile eines Hunk hinzuzufügen, wenn Sie verschiedene Änderungen in eine einzelne Datei aufteilen wollen (suchen Sie auf dieser Seite nach "split").
Nachdem Sie die Änderungen aufgeteilt haben, können Sie nun nur noch die gewünschten Änderungen auswählen.
Ich mag die oben genannten Ansätze nicht. Die Verwendung von Cherry-Pick ist großartig, um eine einzelne Änderung auszuwählen, aber es ist mühsam, wenn man alle Änderungen mit Ausnahme der schlechten einbringen will. Hier ist mein Ansatz.
Es gibt kein --interactive
Argument, das man an git merge übergeben kann.
Hier ist die Alternative:
Sie haben einige Änderungen im Zweig 'feature' und wollen einige, aber nicht alle, auf eine nicht zu schlampige Art und Weise nach 'master' bringen (d.h. Sie wollen nicht jede einzelne Änderung auswählen und übertragen)
git checkout feature
git checkout -b temp
git rebase -i master
# Above will drop you in an editor and pick the changes you want ala:
pick 7266df7 First change
pick 1b3f7df Another change
pick 5bbf56f Last change
# Rebase b44c147..5bbf56f onto b44c147
#
# Commands:
# pick = use commit
# edit = use commit, but stop for amending
# squash = use commit, but meld into previous commit
#
# If you remove a line here THAT COMMIT WILL BE LOST.
# However, if you remove everything, the rebase will be aborted.
#
git checkout master
git pull . temp
git branch -d temp
Also verpacken Sie das einfach in ein Shell-Skript, ändern Sie master in $to und feature in $from und Sie sind startklar:
#!/bin/bash
# git-interactive-merge
from=$1
to=$2
git checkout $from
git checkout -b ${from}_tmp
git rebase -i $to
# Above will drop you in an editor and pick the changes you want
git checkout $to
git pull . ${from}_tmp
git branch -d ${from}_tmp
Die Antwort von 1800 INFORMATION ist völlig korrekt. Als Git-Neuling war "git cherry-pick verwenden" jedoch nicht genug für mich, um dies ohne ein bisschen mehr Graben im Internet herauszufinden, also dachte ich, ich würde eine detailliertere Anleitung posten, falls jemand in einem ähnlichen Boot ist.
Mein Anwendungsfall war, dass ich selektiv Änderungen aus einem anderen Github-Zweig 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.
Erstellen Sie (falls noch nicht vorhanden) eine lokale Verzweigung mit den Änderungen, die Sie einbringen möchten.
$ git branch mybranch <Basiszweig>
Wechseln Sie in diesen Zweig.
$ git checkout mybranch
Ziehen Sie die gewünschten Änderungen aus dem Konto der anderen Person herunter. Wenn Sie das noch nicht getan haben, sollten Sie sie als Remote hinzufügen.
$ git remote add repos-w-changes
Ziehen Sie alles aus ihrem Zweig herunter.
$ git pull repos-w-Änderungen branch-i-want
Sehen Sie sich die Commit-Protokolle an, um zu sehen, welche Änderungen Sie wollen:
$ git log
Wechseln Sie zurück zu dem Zweig, in den Sie die Änderungen übernehmen wollen.
$ git checkout originalbranch
Wählen Sie Ihre Commits einzeln mit den Hashes aus.
$ git cherry-pick -x hash-of-commit
Hattipp: http://www.sourcemage.org/Git_Guide