Wie füge ich ein Unterverzeichnis in Git zusammen?

84

Ist es möglich, nur die Änderungen für ein Unterverzeichnis von einem lokalen Git-Zweig zu einem entfernten Git-Zweig zusammenzuführen, oder ist es "alles oder nichts"?

Zum Beispiel habe ich:

branch-a
 - content-1
 - dir-1
   - content-2

und

branch-b
 - content-1
 - dir-1
   - `content-2

Ich möchte nur den Inhalt von Zweig-a-Verzeichnis-1 mit dem Inhalt von Zweig-b-Verzeichnis-1 zusammenführen.

Brad Gessler
quelle
1
Ich denke, dies ist ein Duplikat von: stackoverflow.com/questions/449541/…
Karl Voigtland

Antworten:

81

Als Alternative zur SO-Frage " Wie fügst du selektive Dateien mit Git-Merge zusammen? " Habe ich gerade diesen GitHub-Thread gefunden, der besser zum Zusammenführen eines ganzen Unterverzeichnisses angepasst werden könnte, basierend auf dem Git-Lesebaum :

  • Mein Repository => cookbooks
    Mein Repository-Zielverzeichnis =>cookbooks/cassandra
  • Remote-Repository => infochimps
    Remote-Repository-Quelle, in die ich zusammengeführt werden möchte cookbooks/cassandra=>infochimps/cookbooks/cassandra

Hier sind die Befehle, mit denen ich sie zusammengeführt habe

  • Fügen Sie das Repository hinzu und rufen Sie es ab
git remote add -f infochimps git: //github.com/infochimps/cluster_chef.git
  • Führen Sie die Zusammenführung durch
git merge --allow-non-related-histories -s our - no-commit infochimps / master

(Dies führt eine Zusammenführung durch, indem die Strategie "Unsere" ( -s ours) verwendet wird, mit der Änderungen aus dem Quellzweig verworfen werden. Dadurch wird die Tatsache aufgezeichnet, die infochimps/masterzusammengeführt wurde, ohne dass tatsächlich eine Datei im Zielzweig geändert wird. )

  • Nur zusammenführen infochimps/cookbooks/cassandraincassandra
git read-tree --prefix = cassandra / -u infochimps / master: kochbücher / cassandra

Dies liest den Baum nur für das erforderliche Quell-Unterverzeichnis, dh cookbooks/cassandraim Upstream-Zweig des Quell- Repositorys.

Beachten Sie, dass der Name des Ziel- Unterverzeichnisses auch lauten sollte cookbooks/cassandra, sonst würden Sie sehen:

fatal: Not a valid object name
  • Übernehmen Sie die Änderung
 git commit -m 'verschmelzen in infochimps cassandra'

Nachtrag

Es ist bizarr, [mich bearbeiten] - aber der read-treeSchritt kann möglicherweise so fehlschlagen:

error: Entry 'infochimps/cookbooks/cassandra/README' overlaps with 'cookbooks/cassandra/README'. Cannot bind.

... auch wenn beide Dateien identisch sind . Dies könnte helfen:

git rm -r cassandra
git read-tree --prefix=cassandra/ -u infochimps/master:cookbooks/cassandra

Aber natürlich überprüfen Sie manuell, ob dies das tut, was Sie wollen.

VonC
quelle
3
@ Martin git-scm.com/docs/git-rev-parse#_specifying_revisions sucht <rev>:<path>, zum Beispiel HEAD:README, :README,master:./README
VonC
6
Der git read-treeSchritt schlägt für mich fehl:error: Entry 'foo/bar/baz.php' overlaps with 'bar/baz.php'. Cannot bind.
Weston Ruter
1
@VonC aber nein, ich brauche die Geschichte. Diese Antwort berücksichtigt nicht den Fall, dass lokale Änderungen an den Dateien im Baum vorgenommen wurden. Es muss also zusammengeführt werden.
Weston Ruter
Für mich tritt der overlaps withoben erwähnte Fehler auch bei identischen Dateien auf . Wie komisch ist das?
Ulidtko
1
@ChrisHalcrow Zum Aufzeichnen der zusammengeführten Tatsache, infochimps/masterohne jedoch eine Datei im Zielzweig zu ändern . Denn im nächsten Schritt git read-tree --prefix=cassandrawird die Änderung vorgenommen. Das endgültige Commit zeichnet den tatsächlichen "Zusammenführungs" -Inhalt auf.
VonC
29

Nehmen wir in meinem Beispiel an, Sie haben eine Zweigstelle 'Quelle' und eine Zweigstelle 'Ziel', die beide Upstream-Versionen von sich selbst widerspiegeln (oder nicht, wenn nur lokal) und auf den neuesten Code gezogen werden. Angenommen, ich möchte das Unterverzeichnis im Repository namens newFeature, das nur im Zweig 'source' vorhanden ist.

git checkout destination
git checkout source newFeature/
git commit -am "Merged the new feature from source to destination branch."
git pull --rebase
git push

Es ist deutlich weniger verworren als alles andere, was ich gesehen habe, und das hat perfekt für mich funktioniert, hier zu finden .

Beachten Sie, dass dies keine echte Zusammenführung ist, sodass Sie nicht die Festschreibungsinformationen zu newFeature im Zielzweig haben, sondern nur die Änderungen an den Dateien in diesem Unterverzeichnis. Da Sie aber vermutlich den gesamten Zweig später wieder zusammenführen oder verwerfen werden, ist dies möglicherweise kein Problem.

Chris Arena
quelle
1
Bewahrt es die Geschichte?
Bibrak
2
@Bibrak Dieser Ansatz bewahrt NICHT die Geschichte. Zumindest nicht mit den aktuellen Befehlen.
Ravi Gidwani
6

Ich habe dies von einem Forenthread bei Eclipse erhalten und es hat wie ein Zauber funktioniert:

git checkout source-branch
git checkout target-branch <directories-or-files-you-do-**NOT**-want> 
git commit
git checkout target-branch
git merge source-branch
Tobiasbayer
quelle
1
Ich habe dies versucht und am Ende ein Verzeichnis aus dem Quellzweig im Zielzweig gefunden, das ich nicht wollte. Obwohl ich es mit den Dirs angegeben habe, wollte ich diesen 2. Befehl nicht.
Marathon
2
Dies wird nicht zusammengeführt, sondern ersetzt den Ordner durch den Ordner aus dem Quellzweig.
Gp2mv3
@ Gp2mv3 Ich denke, es sieht solide aus. checkoutmacht die Ordner gleich => Unterschied ist nur Unordner checkout=> mergeUnterschied. Es ist eine gültige Strategie.
Caveman
3

Angesichts des OP-Szenarios, in dem sie zwei Zweige haben, aber nur die Historie von dir-1 von Zweig-a in Zweig-b zusammenführen möchten :

# Make sure you are in the branch with the changes you want
git checkout branch-a

# Split the desired folder into its own temporary branch
# This replays all commits, so it could take a while
git subtree split -P dir-1 -b temp-branch

# Enter the branch where you want to merge the desired changes into
git checkout branch-b

# Merge the changes from the temporary branch
git subtree merge -P dir-1 temp-branch

# Handle any conflicts
git mergetool

# Commit
git commit -am "Merged dir-1 changes from branch-a"

# Delete temp-branch
git branch -d temp-branch
xno
quelle
0

Erstellen Sie ein Git-Repository, das sowohl Zweig-a als auch Zweig-b enthält:

git checkout branch-a
git diff branch-b dir-1 > a.diff
patch -R -p1 < a.diff
Sun Yin
quelle
14
Diese Antwort benötigt weitere Informationen. Was ist der tatsächliche Code gegen Kommentare?
Qodeninja
2
Der Anforderer möchte zusammenführen. Wenn Sie einen Patch verwenden, um die Änderungen zu übernehmen, werden alle Commits automatisch in einem Patch zusammengefasst, und der Verlauf geht verloren.
Eric
0

Verwenden git cherry-pickSie diese Option, um die gewünschten Commits auszuwählen und nur diese Commits zusammenzuführen. Der wichtigste Trick dabei ist, diese Commits auf einfache Weise zu erhalten (damit Sie sie nicht herausfinden müssen, indem Sie das Git-Protokoll manuell überprüfen und von Hand eingeben). So geht's: Verwenden Sie git logdiese Option, um die SHA-1- ID des Commits wie folgt zu drucken :

git log ^<commit-a> <commit-b> --pretty=format:"%h" --reverse -- <subdir>

'commit-a' ist das Commit unmittelbar vor dem Startpunkt des zusammenzuführenden Zweigs, und 'commit-b' ist das letzte Commit für den zusammenzuführenden Zweig. '--reverse' druckt diese Commits in umgekehrter Reihenfolge, um sie später zu pflücken.

Dann mach es wie:

git cherry-pick $(git log ^<commit-a> <commit-b> --pretty=format:"%h" --reverse -- <subdir>)

Es ist zwei Schritte, einfach und stabil!

Robert
quelle
Hervorragende und einzige Möglichkeit, ein einzelnes Verzeichnis aus einem anderen Zweig zusammenzuführen und die Geschichte zu bewahren. aber ... ... wenn Sie nur ein Commit möchten, erstellen Sie einen Zweig aus allen Commits des ersten Befehls und führen Sie diesen neuen Zweig in einem Squash-Merge zusammen ...
Tom
1
Dies setzt voraus, dass die gefundenen Commits nur das betreffende Verzeichnis betreffen. Wenn sich ein Commit sowohl auf das Verzeichnis auswirkt, das Sie zusammenführen möchten, als auch auf das Verzeichnis, das Sie nicht zusammenführen möchten, wird dies zu viel Auswahl treffen.
Scott
Two steps, simple and stable!überhaupt nicht einfach :)
Rafa
Wie denkst du, ist es einfach? @ Rafa
Robert
@ Robert Ich wollte nicht implizieren, dass deine Antwort nicht einfach ist. Der Fehler liegt auf der Hand git, der eine schreckliche Schnittstelle und ein schreckliches mentales Modell voller Geheimnisse und zufälliger Namen und Bedeutungen hat.
Rafa