Wie fügst du zwei Git-Repositorys zusammen?


1621

Stellen Sie sich das folgende Szenario vor:

Ich habe ein kleines experimentelles Projekt A in einem eigenen Git-Repo entwickelt. Es ist jetzt gereift und ich möchte, dass A Teil des größeren Projekts B ist, das über ein eigenes großes Repository verfügt. Ich möchte jetzt A als Unterverzeichnis von B hinzufügen.

Wie verschmelze ich A mit B, ohne auf irgendeiner Seite die Geschichte zu verlieren?


8
Wenn Sie nur versuchen, zwei Repositorys zu einem zu kombinieren, ohne beide Repositorys behalten zu müssen, werfen Sie einen Blick auf diese Frage: stackoverflow.com/questions/13040958/…
Flimm

Antworten:


437

Ein einzelner Zweig eines anderen Repositorys kann einfach unter ein Unterverzeichnis gestellt werden, wobei der Verlauf beibehalten wird. Zum Beispiel:

git subtree add --prefix=rails git://github.com/rails/rails.git master

Dies wird als einzelnes Commit angezeigt, bei dem alle Dateien des Rails-Hauptzweigs zum Verzeichnis "Rails" hinzugefügt werden. Der Titel des Commits enthält jedoch einen Verweis auf den alten Verlaufsbaum:

Fügen Sie 'Rails /' aus Commit hinzu <rev>

Wo <rev>ist ein SHA-1-Commit-Hash? Sie können immer noch den Verlauf sehen, einige Änderungen beschuldigen.

git log <rev>
git blame <rev> -- README.md

Beachten Sie, dass Sie das Verzeichnispräfix von hier aus nicht sehen können, da dies ein tatsächlicher alter Zweig ist, der intakt bleibt. Sie sollten dies wie ein übliches Commit zum Verschieben von Dateien behandeln: Sie benötigen einen zusätzlichen Sprung, wenn Sie es erreichen.

# finishes with all files added at once commit
git log rails/README.md

# then continue from original tree
git log <rev> -- README.md

Es gibt komplexere Lösungen, wie dies manuell zu tun oder den Verlauf neu zu schreiben, wie in anderen Antworten beschrieben.

Der Befehl git-subtree ist Teil des offiziellen git-contrib. Einige Paketmanager installieren ihn standardmäßig (OS X Homebrew). Möglicherweise müssen Sie es jedoch zusätzlich zu git selbst installieren.


2
Hier sind Anweisungen, wie Git SubTree (Stand : Juni 2013) zu installieren: stackoverflow.com/a/11613541/694469 (und ich ersetzt git co v1.7.11.3 mit ... v1.8.3).
KajMagnus

1
Vielen Dank für die Hinweise zur folgenden Antwort. Ab Git 1.8.4 ist 'Teilbaum' noch nicht enthalten (zumindest nicht auf dem Ubuntu 12.04 Git ppa (ppa: git-core / ppa))
Matt Klein

1
Ich kann bestätigen, dass danach git log rails/somefileder Commit-Verlauf dieser Datei mit Ausnahme des Merge-Commits nicht mehr angezeigt wird. Überprüfen Sie, wie @artfulrobot vorgeschlagen hat, die Antwort von Greg Hewgill . Möglicherweise müssen Sie git filter-branchdas Repo verwenden, das Sie einschließen möchten.
Jifeng Zhang

6
Oder lesen Sie Eric Lees "Zusammenführen von zwei Git-Repositories zu einem Repository, ohne den Dateiversionsverlauf zu verlieren" saintgimp.org/2013/01/22/…
Jifeng Zhang

4
Wie andere gesagt haben, git subtreedarf nicht tun, was Sie denken! Sehen Sie hier für eine vollständige Lösung.
Paul Draper

1907

Wenn Sie zusammenführen möchten project-ain project-b:

cd path/to/project-b
git remote add project-a path/to/project-a
git fetch project-a --tags
git merge --allow-unrelated-histories project-a/master # or whichever branch you want to merge
git remote remove project-a

Entnommen aus: git verschiedene Repositories zusammenführen?

Diese Methode hat bei mir ziemlich gut funktioniert, sie ist kürzer und meiner Meinung nach viel sauberer.

Wenn Sie project-ain ein Unterverzeichnis einfügen möchten , können Sie verwenden git-filter-repo( filter-branchwird davon abgeraten ). Führen Sie die folgenden Befehle vor den obigen Befehlen aus:

cd path/to/project-a
git filter-repo --to-subdirectory-filter project-a

Ein Beispiel für das Zusammenführen von zwei großen Repositorys, wobei eines davon in einem Unterverzeichnis abgelegt wird: https://gist.github.com/x-yuri/9890ab1079cf4357d6f269d073fd9731

Hinweis: Der --allow-unrelated-historiesParameter existiert nur seit git> = 2.9. Siehe Git - git merge Documentation / --allow-non-related-histories

Update : --tagsWie von @jstadler vorgeschlagen hinzugefügt, um Tags beizubehalten.


8
Das hat das Geschäft für mich gemacht. Hat beim ersten Mal wie ein Zauber mit nur einem Konflikt in der .gitignore-Datei funktioniert! Es hat die Commit-Geschichte perfekt bewahrt. Das große Plus gegenüber anderen Ansätzen - neben der Einfachheit - ist, dass damit kein fortlaufender Verweis auf das zusammengeführte Repo erforderlich ist. Eine Sache, auf die Sie jedoch achten sollten - wenn Sie ein iOS-Entwickler wie ich sind - ist, sehr vorsichtig zu sein, um die Projektdatei des Ziel-Repos in den Arbeitsbereich zu legen.
Max MacLeod

30
Vielen Dank. Hat für mich gearbeitet. Ich musste das zusammengeführte Verzeichnis in einen Unterordner verschieben, also nachdem ich die obigen Schritte ausgeführt hatte, benutzte ich einfachgit mv source-dir/ dest/new-source-dir
Sid

13
Der git mergeSchritt schlägt hier mit fehl fatal: refusing to merge unrelated histories; --allow-unrelated-historiesbehebt das wie in den Dokumenten erklärt .
ssc

19
--allow-unrelated-historieswurde in git 2.9 eingeführt . In früheren Versionen war dies das Standardverhalten.
Douglas Royds

11
Kürzere : git fetch /path/to/project-a master; git merge --allow-unrelated-histories FETCH_HEAD.
Bis zum

614

Hier sind zwei mögliche Lösungen:

Submodule

Kopieren Sie entweder Repository A in ein separates Verzeichnis in größerem Projekt B oder (vielleicht besser) klonen Sie Repository A in ein Unterverzeichnis in Projekt B. Verwenden Sie dann das Git-Submodul , um dieses Repository zu einem Submodul zu machen eines Repositorys B .

Dies ist eine gute Lösung für lose gekoppelte Repositorys, bei denen die Entwicklung in Repository A fortgesetzt wird und der größte Teil der Entwicklung eine separate eigenständige Entwicklung in A ist. Siehe auch SubmoduleSupport und GitSubmoduleTutorial Seiten im Git-Wiki.

Teilbaum zusammenführen

Sie können das Repository A mithilfe der Teilbaum-Zusammenführungsstrategie in ein Unterverzeichnis eines Projekts B zusammenführen . Dies wird in Subtree Merging and You von Markus Prinz beschrieben.

git remote add -f Bproject /path/to/B
git merge -s ours --allow-unrelated-histories --no-commit Bproject/master
git read-tree --prefix=dir-B/ -u Bproject/master
git commit -m "Merge B project as our subdirectory"
git pull -s subtree Bproject master

(Möglichkeit --allow-unrelated-histories wird für Git> = 2.9.0 benötigt.)

Oder Sie können das Git-Teilbaum- Tool ( Repository auf GitHub ) von apenwarr (Avery Pennarun) verwenden, das beispielsweise in seinem Blog-Beitrag angekündigt wurde. Eine neue Alternative zu Git-Submodulen: Git-Teilbaum .


Ich denke, in Ihrem Fall (A soll Teil eines größeren Projekts B sein) wäre die richtige Lösung die Verwendung der Teilbaumzusammenführung .


1
Dies funktioniert und scheint den Verlauf beizubehalten, aber nicht so, dass Sie ihn verwenden könnten, um Dateien zu unterscheiden oder durch die Zusammenführung zu halbieren. Vermisse ich einen Schritt?
Jettero

55
das ist unvollständig . Ja, Sie erhalten eine Menge Commits, die sich jedoch nicht mehr auf die richtigen Pfade beziehen. git log dir-B/somefilezeigt nichts außer der einen Zusammenführung. Siehe Greg Hewgills Antwort bezieht sich auf dieses wichtige Thema.
Artfulrobot

2
WICHTIG: git pull --no-rebase -s Teilbaum Bproject master Wenn Sie dies nicht tun und Pull so eingestellt ist, dass es automatisch neu basiert, wird "Objekt konnte nicht analysiert werden" angezeigt. Siehe osdir.com/ml/git/2009-07/msg01576.html
Eric Bowman - abstracto -

4
Diese Antwort kann verwirrend sein, da sie B als zusammengeführten Teilbaum enthält, wenn es sich bei der Frage um A handelt. Ergebnis eines Kopierens und Einfügens?
vfclists

11
Wenn Sie versuchen, einfach zwei Repositorys zusammenzukleben, sind Submodule und Zusammenführungen von Teilbäumen das falsche Werkzeug, da sie nicht den gesamten Dateiversionsverlauf beibehalten (wie andere Kommentatoren festgestellt haben). Siehe stackoverflow.com/questions/13040958/… .
Eric Lee

194

Der Submodul-Ansatz ist gut, wenn Sie das Projekt separat verwalten möchten. Wenn Sie jedoch wirklich beide Projekte in demselben Repository zusammenführen möchten, müssen Sie etwas mehr Arbeit erledigen.

Das erste wäre, git filter-branchdie Namen aller Elemente im zweiten Repository so umzuschreiben, dass sie sich im Unterverzeichnis befinden, in dem sie enden sollen. Anstatt also foo.c, bar.htmlwürden Sie haben projb/foo.cundprojb/bar.html .

Dann sollten Sie in der Lage sein, Folgendes zu tun:

git remote add projb [wherever]
git pull projb

Das git pullwird ein git fetchgefolgt von einem tun git merge. Es sollte keine Konflikte geben, wenn das Repository, in das Sie ziehen, noch keine hatprojb/ Verzeichnis hat.

Weitere Suche zeigt an, dass etwas Ähnliches getan wurde, um gitksich zusammenzuschließen git. Junio ​​C Hamano schreibt hier darüber: http://www.mail-archive.com/git@vger.kernel.org/msg03395.html


4
Die Zusammenführung von
Teilbäumen

8
Ich würde gerne wissen, wie git filter-branchman dies erreicht. In der Manpage heißt es umgekehrt: Subdir / zur Wurzel machen, aber nicht umgekehrt.
Artfulrobot

31
Diese Antwort wäre großartig, wenn sie erklären würde, wie man mit Filter-Branch das gewünschte Ergebnis
erzielt

14
Ich fand hier, wie man Filter-Branch verwendet: stackoverflow.com/questions/4042816/…
David Minor

3
In dieser Antwort finden Sie die Implementierung von Gregs Gliederung.
Paul Draper

75

git-subtree ist schön, aber es ist wahrscheinlich nicht das, was Sie wollen.

Wenn zum Beispiel projectAdas Verzeichnis , in B erstellt, nach git subtree,

git log projectA

listet nur ein Commit auf: das Zusammenführen. Die Commits aus dem zusammengeführten Projekt gelten für verschiedene Pfade, sodass sie nicht angezeigt werden.

Greg Hewgills Antwort kommt am nächsten, obwohl sie eigentlich nicht sagt, wie man die Pfade umschreibt.


Die Lösung ist überraschend einfach.

(1) In A,

PREFIX=projectA #adjust this

git filter-branch --index-filter '
    git ls-files -s |
    sed "s,\t,&'"$PREFIX"'/," |
    GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info &&
    mv $GIT_INDEX_FILE.new $GIT_INDEX_FILE
' HEAD

Hinweis: Dadurch wird der Verlauf neu geschrieben. Wenn Sie dieses Repo A weiterhin verwenden möchten, möchten Sie möglicherweise zuerst eine Wegwerfkopie davon klonen (kopieren).

Hinweis Vorteil: Sie müssen das Ersatzskript im Befehl sed ändern, wenn Sie in Dateinamen oder Pfaden Nicht-ASCII-Zeichen (oder weiße Zeichen) verwenden. In diesem Fall beginnt der Dateispeicherort in einem von "ls-files -s" erstellten Datensatz mit einem Anführungszeichen.

(2) Führen Sie dann in B aus

git pull path/to/A

Voila! Sie haben ein projectAVerzeichnis in B. Wenn Sie ausführen git log projectA, werden alle Commits von A angezeigt.


In meinem Fall wollte ich zwei Unterverzeichnisse projectAund projectB. In diesem Fall habe ich auch Schritt (1) zu B gemacht.


1
Sie haben anscheinend Ihre Antwort von stackoverflow.com/a/618113/586086 kopiert ?
Andrew Mao

1
@ AndrewMao, ich denke schon ... ich kann mich eigentlich nicht erinnern. Ich habe dieses Skript ziemlich oft benutzt.
Paul Draper

6
Ich würde hinzufügen, dass \ t unter OS X nicht funktioniert und Sie <tab>
Muneeb Ali

2
"$GIT_INDEX_FILE"muss (zweimal) in Anführungszeichen gesetzt werden, sonst schlägt Ihre Methode fehl, wenn z. B. der Pfad Leerzeichen enthält.
Rob W

4
Wenn Sie sich fragen, um ein <tab> in osx einzufügen, müssen SieCtrl-V <tab>
casey

48

Wenn beide Repositorys dieselbe Art von Dateien haben (wie zwei Rails-Repositorys für verschiedene Projekte), können Sie Daten des sekundären Repositorys in Ihr aktuelles Repository abrufen:

git fetch git://repository.url/repo.git master:branch_name

und führen Sie es dann zum aktuellen Repository zusammen:

git merge --allow-unrelated-histories branch_name

Wenn Ihre Git-Version kleiner als 2.9 ist, entfernen Sie --allow-unrelated-histories.

Danach können Konflikte auftreten. Sie können sie beispielsweise mit auflösen git mergetool. kdiff3kann nur mit Tastatur verwendet werden, so dass 5 Konfliktdateien beim Lesen des Codes nur wenige Minuten dauern.

Denken Sie daran, die Zusammenführung zu beenden:

git commit

25

Ich habe bei der Verwendung von Merge immer wieder den Verlauf verloren, sodass ich letztendlich Rebase verwendet habe, da in meinem Fall die beiden Repositorys so unterschiedlich sind, dass sie nicht bei jedem Commit zusammengeführt werden:

git clone git@gitorious/projA.git projA
git clone git@gitorious/projB.git projB

cd projB
git remote add projA ../projA/
git fetch projA 
git rebase projA/master HEAD

=> Konflikte lösen, dann so oft wie nötig fortfahren ...

git rebase --continue

Dies führt dazu, dass ein Projekt alle Commits von projA enthält, gefolgt von Commits von projB


25

In meinem Fall hatte ich ein my-pluginRepository und ein main-projectRepository, und ich wollte so tun, als wäre my-plugindas immer im pluginsUnterverzeichnis von entwickelt worden main-project.

Grundsätzlich habe ich den Verlauf des my-pluginRepositorys so umgeschrieben , dass die gesamte Entwicklung im plugins/my-pluginUnterverzeichnis stattfand. Dann habe ich die Entwicklungsgeschichte von my-pluginin die main-projectGeschichte aufgenommen und die beiden Bäume zusammengeführt. Da war noch kein plugins/my-pluginVerzeichnis in dermain-project Repository , war dies eine triviale Zusammenführung ohne Konflikte. Das resultierende Repository enthielt den gesamten Verlauf beider Originalprojekte und hatte zwei Wurzeln.

TL; DR

$ cp -R my-plugin my-plugin-dirty
$ cd my-plugin-dirty
$ git filter-branch -f --tree-filter "zsh -c 'setopt extended_glob && setopt glob_dots && mkdir -p plugins/my-plugin && (mv ^(.git|plugins) plugins/my-plugin || true)'" -- --all
$ cd ../main-project
$ git checkout master
$ git remote add --fetch my-plugin ../my-plugin-dirty
$ git merge my-plugin/master --allow-unrelated-histories
$ cd ..
$ rm -rf my-plugin-dirty

Lange Version

Erstellen Sie zunächst eine Kopie des my-pluginRepositorys, da wir den Verlauf dieses Repositorys neu schreiben werden.

Navigieren Sie nun zum Stammverzeichnis des my-pluginRepositorys, überprüfen Sie (wahrscheinlich master) Ihren Hauptzweig und führen Sie den folgenden Befehl aus. Natürlich sollten Sie ersetzen my-pluginund pluginswas auch immer Ihre tatsächlichen Namen sind.

$ git filter-branch -f --tree-filter "zsh -c 'setopt extended_glob && setopt glob_dots && mkdir -p plugins/my-plugin && (mv ^(.git|plugins) plugins/my-plugin || true)'" -- --all

Nun zu einer Erklärung. git filter-branch --tree-filter (...) HEADführt den (...)Befehl für jedes Commit aus, von dem aus erreichbar ist HEAD. Beachten Sie, dass dies direkt mit den für jedes Commit gespeicherten Daten zusammenhängt, sodass wir uns nicht um die Begriffe "Arbeitsverzeichnis", "Index", "Staging" usw. kümmern müssen.

Wenn Sie einen filter-branchfehlgeschlagenen Befehl ausführen , bleiben einige Dateien im .gitVerzeichnis zurück, und beim nächsten Versuch filter-branchwird dies beanstandet, es sei denn, Sie geben die -fOption an filter-branch.

Was den eigentlichen Befehl angeht, hatte ich nicht viel Glück, das bashzu tun, was ich wollte, also verwende ich stattdessen zsh -c, zshum einen Befehl auszuführen. Zuerst setze ich die extended_globOption, die die ^(...)Syntax im mvBefehl glob_dotsaktiviert , sowie die Option, mit der ich Punktedateien (wie .gitignore) mit einem glob ( ^(...)) auswählen kann .

Als nächstes benutze ich den mkdir -pBefehl sowohl zu schaffen pluginsund plugins/my-pluginzugleich.

Schließlich verwende ich die Funktion zsh"Negative Glob" ^(.git|plugins), um alle Dateien im Stammverzeichnis des Repositorys mit Ausnahme .gitdes neu erstellten my-pluginOrdners abzugleichen. (Ein Ausschluss ist hier .gitmöglicherweise nicht erforderlich, aber der Versuch, ein Verzeichnis in sich selbst zu verschieben, ist ein Fehler.)

In meinem Repository enthielt das anfängliche Festschreiben keine Dateien, sodass der mvBefehl beim ersten Festschreiben einen Fehler zurückgab (da nichts zum Verschieben verfügbar war). Deshalb habe ich ein hinzugefügt || true, git filter-branchdamit nicht abgebrochen wird.

Die --allOption weist filter-branchan, den Verlauf für alle Zweige im Repository neu zu schreiben , und das Extra --muss angeben git, dass er als Teil der Optionsliste für neu zu schreibende Zweige und nicht als Option für sich filter-branchselbst interpretiert werden soll .

Navigieren Sie nun zu Ihrem main-projectRepository und überprüfen Sie den Zweig, in den Sie zusammenführen möchten. Fügen Sie Ihre lokale Kopie des my-pluginRepositorys (mit geändertem Verlauf) als Remote von hinzu main-project:

$ git remote add --fetch my-plugin $PATH_TO_MY_PLUGIN_REPOSITORY

Sie haben jetzt zwei nicht verwandte Bäume in Ihrem Commit-Verlauf, die Sie mithilfe von:

$ git log --color --graph --decorate --all

Verwenden Sie zum Zusammenführen Folgendes:

$ git merge my-plugin/master --allow-unrelated-histories

Beachten Sie, dass in Git vor 2.9.0 die --allow-unrelated-historiesOption nicht vorhanden ist. Wenn Sie eine dieser Versionen verwenden, lassen Sie einfach die Option weg: Die Fehlermeldung, die dies --allow-unrelated-historiesverhindert, wurde auch in 2.9.0 hinzugefügt.

Sie sollten keine Zusammenführungskonflikte haben. Wenn Sie dies tun, bedeutet dies wahrscheinlich, dass entweder der filter-branchBefehl nicht ordnungsgemäß funktioniert hat oder bereits ein plugins/my-pluginVerzeichnis vorhanden war main-project.

Stellen Sie sicher, dass Sie eine erklärende Commit-Nachricht für zukünftige Mitwirkende eingeben, die sich fragen, was Hackery vor sich hat, um ein Repository mit zwei Wurzeln zu erstellen.

Mit dem obigen git logBefehl können Sie das neue Festschreibungsdiagramm visualisieren, das zwei Root-Festschreibungen enthalten sollte . Beachten Sie, dass nur der masterZweig zusammengeführt wird . Dies bedeutet, dass Sie, wenn Sie wichtige Arbeit an anderen my-pluginZweigen haben, die Sie in den main-projectBaum einbinden möchten, die my-pluginFernbedienung erst löschen sollten , wenn Sie diese Zusammenführungen durchgeführt haben. Wenn Sie dies nicht tun, befinden sich die Commits aus diesen Zweigen weiterhin im main-projectRepository, einige sind jedoch nicht erreichbar und können möglicherweise nicht ordnungsgemäß gespeichert werden. (Außerdem müssen Sie von SHA auf sie verweisen, da durch das Löschen einer Fernbedienung die Fernverfolgungszweige entfernt werden.)

Optional können Sie my-plugindie my-pluginFernbedienung entfernen , nachdem Sie alles zusammengeführt haben, was Sie behalten möchten :

$ git remote remove my-plugin

Sie können jetzt die Kopie des my-pluginRepositorys, dessen Verlauf Sie geändert haben, sicher löschen . In meinem Fall habe ich dem realen my-pluginRepository auch einen Verfallshinweis hinzugefügt, nachdem die Zusammenführung abgeschlossen und verschoben wurde.


Getestet unter Mac OS X El Capitan mit git --version 2.9.0und zsh --version 5.2. Ihr Kilometerstand kann variieren.

Verweise:


1
Woher --allow-unrelated-historieskommen sie?
Bis zum

3
@MarceloFilho Check man git-merge. Standardmäßig lehnt der Befehl git merge das Zusammenführen von Historien ab, die keinen gemeinsamen Vorfahren haben. Diese Option kann verwendet werden, um diese Sicherheit zu überschreiben, wenn Historien von zwei Projekten zusammengeführt werden, die ihr Leben unabhängig voneinander begonnen haben. Da dies sehr selten vorkommt, ist standardmäßig keine Konfigurationsvariable vorhanden, die dies aktiviert, und wird nicht hinzugefügt.
Radon Rosborough

Sollte am verfügbar sein git version 2.7.2.windows.1?
Bis zum

2
@MarceloFilho Dies wurde in 2.9.0 hinzugefügt, aber in älteren Versionen sollten Sie die Option nicht übergeben müssen (es wird einfach funktionieren). github.com/git/git/blob/…
Radon Rosborough

Das hat gut funktioniert. Und ich konnte den Filterzweig verwenden, um die Dateinamen vor dem Zusammenführen an die gewünschte Stelle im Baum zu schreiben. Ich nehme an, es ist mehr Arbeit erforderlich, wenn Sie den Verlauf neben dem Hauptzweig verschieben müssen.
CodeDr

9

Ich habe seit Tagen versucht, das Gleiche zu tun, ich benutze Git 2.7.2. Teilbaum bewahrt die Geschichte nicht.

Sie können diese Methode verwenden, wenn Sie das alte Projekt nicht mehr verwenden.

Ich würde vorschlagen, dass Sie zuerst B verzweigen und in der Verzweigung arbeiten.

Hier sind die Schritte ohne Verzweigung:

cd B

# You are going to merge A into B, so first move all of B's files into a sub dir
mkdir B

# Move all files to B, till there is nothing in the dir but .git and B
git mv <files> B

git add .

git commit -m "Moving content of project B in preparation for merge from A"


# Now merge A into B
git remote add -f A <A repo url>

git merge A/<branch>

mkdir A

# move all the files into subdir A, excluding .git
git mv <files> A

git commit -m "Moved A into subdir"


# Move B's files back to root    
git mv B/* ./

rm -rf B

git commit -m "Reset B to original state"

git push

Wenn Sie jetzt eine der Dateien in Unterverzeichnis A protokollieren, erhalten Sie den vollständigen Verlauf

git log --follow A/<file>

Dies war der Beitrag, der mir dabei half:

http://saintgimp.org/2013/01/22/merging-two-git-repositories-into-one-repository-without-losing-file-history/


8

Wenn Sie die Dateien aus einem Zweig in Repo B in einen Teilbaum von Repo A einfügen und auch den Verlauf beibehalten möchten , lesen Sie weiter. (Im folgenden Beispiel gehe ich davon aus, dass der Hauptzweig von Repo B mit dem Hauptzweig von Repo A zusammengeführt werden soll.)

Führen Sie in Repo A zunächst die folgenden Schritte aus, um Repo B verfügbar zu machen:

git remote add B ../B # Add repo B as a new remote.
git fetch B

Jetzt erstellen wir eine brandneue Filiale (mit nur einem Commit) in Repo A, die wir aufrufen new_b_root. Das resultierende Commit enthält die Dateien, die beim ersten Commit des Hauptzweigs von Repo B festgeschrieben wurden, aber in einem Unterverzeichnis namens aufgerufen wurden path/to/b-files/.

git checkout --orphan new_b_root master
git rm -rf . # Remove all files.
git cherry-pick -n `git rev-list --max-parents=0 B/master`
mkdir -p path/to/b-files
git mv README path/to/b-files/
git commit --date="$(git log --format='%ai' $(git rev-list --max-parents=0 B/master))"

Erläuterung: Die --orphanOption zum Befehl checkout checkt die Dateien aus dem Hauptzweig von A aus, erstellt jedoch kein Commit. Wir hätten jedes Commit auswählen können, da wir als nächstes sowieso alle Dateien löschen. Dann, ohne noch ein -nCommit ( ) durchzuführen, wählen wir das erste Commit aus dem Hauptzweig von B aus. (Der Cherry-Pick behält die ursprüngliche Festschreibungsnachricht bei, die ein direktes Auschecken nicht zu tun scheint.) Anschließend erstellen wir den Teilbaum, in den alle Dateien aus Repo B eingefügt werden sollen. Anschließend müssen alle Dateien verschoben werden, die in das Verzeichnis eingefügt wurden Kirschbaum zum Teilbaum. Im obigen Beispiel muss nur eine READMEDatei verschoben werden. Dann schreiben wir unser B-Repo-Root-Commit fest und behalten gleichzeitig den Zeitstempel des ursprünglichen Commits bei.

Jetzt erstellen wir einen neuen B/masterZweig über dem neu erstellten new_b_root. Wir nennen die neue Niederlassung b:

git checkout -b b B/master
git rebase -s recursive -Xsubtree=path/to/b-files/ new_b_root

Jetzt verschmelzen wir unseren bZweig zu A/master:

git checkout master
git merge --allow-unrelated-histories --no-commit b
git commit -m 'Merge repo B into repo A.'

Schließlich können Sie die Bentfernten und temporären Zweige entfernen :

git remote remove B
git branch -D new_b_root b

Das endgültige Diagramm hat eine Struktur wie folgt:

Geben Sie hier die Bildbeschreibung ein


Tolle Antwort, danke! Ich habe in den anderen Antworten mit "git subtree" oder "merge --allow-non-related-histories" von Andresch Serj wirklich vermisst, dass das Unterverzeichnis das Protokoll nicht hatte.
Ilendir

8

Ich habe hier viele Informationen über Stack OverFlow usw. gesammelt und es geschafft, ein Skript zusammenzustellen, das das Problem für mich löst.

Die Einschränkung besteht darin, dass nur der Zweig "Entwickeln" jedes Repositorys berücksichtigt und in einem separaten Verzeichnis in einem völlig neuen Repository zusammengeführt wird.

Tags und andere Zweige werden ignoriert - dies ist möglicherweise nicht das, was Sie wollen.

Das Skript verarbeitet sogar Feature-Zweige und -Tags und benennt sie im neuen Projekt um, damit Sie wissen, woher sie stammen.

#!/bin/bash
#
################################################################################
## Script to merge multiple git repositories into a new repository
## - The new repository will contain a folder for every merged repository
## - The script adds remotes for every project and then merges in every branch
##   and tag. These are renamed to have the origin project name as a prefix
##
## Usage: mergeGitRepositories.sh <new_project> <my_repo_urls.lst>
## - where <new_project> is the name of the new project to create
## - and <my_repo_urls.lst> is a file contaning the URLs to the respositories
##   which are to be merged on separate lines.
##
## Author: Robert von Burg
##            eitch@eitchnet.ch
##
## Version: 0.3.2
## Created: 2018-02-05
##
################################################################################
#

# disallow using undefined variables
shopt -s -o nounset

# Script variables
declare SCRIPT_NAME="${0##*/}"
declare SCRIPT_DIR="$(cd ${0%/*} ; pwd)"
declare ROOT_DIR="$PWD"
IFS=$'\n'

# Detect proper usage
if [ "$#" -ne "2" ] ; then
  echo -e "ERROR: Usage: $0 <new_project> <my_repo_urls.lst>"
  exit 1
fi


## Script variables
PROJECT_NAME="${1}"
PROJECT_PATH="${ROOT_DIR}/${PROJECT_NAME}"
TIMESTAMP="$(date +%s)"
LOG_FILE="${ROOT_DIR}/${PROJECT_NAME}_merge.${TIMESTAMP}.log"
REPO_FILE="${2}"
REPO_URL_FILE="${ROOT_DIR}/${REPO_FILE}"


# Script functions
function failed() {
  echo -e "ERROR: Merging of projects failed:"
  echo -e "ERROR: Merging of projects failed:" >>${LOG_FILE} 2>&1
  echo -e "$1"
  exit 1
}

function commit_merge() {
  current_branch="$(git symbolic-ref HEAD 2>/dev/null)"
  if [[ ! -f ".git/MERGE_HEAD" ]] ; then
    echo -e "INFO:   No commit required."
    echo -e "INFO:   No commit required." >>${LOG_FILE} 2>&1
  else
    echo -e "INFO:   Committing ${sub_project}..."
    echo -e "INFO:   Committing ${sub_project}..." >>${LOG_FILE} 2>&1
    if ! git commit -m "[Project] Merged branch '$1' of ${sub_project}" >>${LOG_FILE} 2>&1 ; then
      failed "Failed to commit merge of branch '$1' of ${sub_project} into ${current_branch}"
    fi
  fi
}


# Make sure the REPO_URL_FILE exists
if [ ! -e "${REPO_URL_FILE}" ] ; then
  echo -e "ERROR: Repo file ${REPO_URL_FILE} does not exist!"
  exit 1
fi


# Make sure the required directories don't exist
if [ -e "${PROJECT_PATH}" ] ; then
  echo -e "ERROR: Project ${PROJECT_NAME} already exists!"
  exit 1
fi


# create the new project
echo -e "INFO: Logging to ${LOG_FILE}"
echo -e "INFO: Creating new git repository ${PROJECT_NAME}..."
echo -e "INFO: Creating new git repository ${PROJECT_NAME}..." >>${LOG_FILE} 2>&1
echo -e "===================================================="
echo -e "====================================================" >>${LOG_FILE} 2>&1
cd ${ROOT_DIR}
mkdir ${PROJECT_NAME}
cd ${PROJECT_NAME}
git init
echo "Initial Commit" > initial_commit
# Since this is a new repository we need to have at least one commit
# thus were we create temporary file, but we delete it again.
# Deleting it guarantees we don't have conflicts later when merging
git add initial_commit
git commit --quiet -m "[Project] Initial Master Repo Commit"
git rm --quiet initial_commit
git commit --quiet -m "[Project] Initial Master Repo Commit"
echo


# Merge all projects into the branches of this project
echo -e "INFO: Merging projects into new repository..."
echo -e "INFO: Merging projects into new repository..." >>${LOG_FILE} 2>&1
echo -e "===================================================="
echo -e "====================================================" >>${LOG_FILE} 2>&1
for url in $(cat ${REPO_URL_FILE}) ; do

  if [[ "${url:0:1}" == '#' ]] ; then
    continue
  fi

  # extract the name of this project
  export sub_project=${url##*/}
  sub_project=${sub_project%*.git}

  echo -e "INFO: Project ${sub_project}"
  echo -e "INFO: Project ${sub_project}" >>${LOG_FILE} 2>&1
  echo -e "----------------------------------------------------"
  echo -e "----------------------------------------------------" >>${LOG_FILE} 2>&1

  # Fetch the project
  echo -e "INFO:   Fetching ${sub_project}..."
  echo -e "INFO:   Fetching ${sub_project}..." >>${LOG_FILE} 2>&1
  git remote add "${sub_project}" "${url}"
  if ! git fetch --tags --quiet ${sub_project} >>${LOG_FILE} 2>&1 ; then
    failed "Failed to fetch project ${sub_project}"
  fi

  # add remote branches
  echo -e "INFO:   Creating local branches for ${sub_project}..."
  echo -e "INFO:   Creating local branches for ${sub_project}..." >>${LOG_FILE} 2>&1
  while read branch ; do
    branch_ref=$(echo $branch | tr " " "\t" | cut -f 1)
    branch_name=$(echo $branch | tr " " "\t" | cut -f 2 | cut -d / -f 3-)

    echo -e "INFO:   Creating branch ${branch_name}..."
    echo -e "INFO:   Creating branch ${branch_name}..." >>${LOG_FILE} 2>&1

    # create and checkout new merge branch off of master
    if ! git checkout -b "${sub_project}/${branch_name}" master >>${LOG_FILE} 2>&1 ; then failed "Failed preparing ${branch_name}" ; fi
    if ! git reset --hard ; then failed "Failed preparing ${branch_name}" >>${LOG_FILE} 2>&1 ; fi
    if ! git clean -d --force ; then failed "Failed preparing ${branch_name}" >>${LOG_FILE} 2>&1 ; fi

    # Merge the project
    echo -e "INFO:   Merging ${sub_project}..."
    echo -e "INFO:   Merging ${sub_project}..." >>${LOG_FILE} 2>&1
    if ! git merge --allow-unrelated-histories --no-commit "remotes/${sub_project}/${branch_name}" >>${LOG_FILE} 2>&1 ; then
      failed "Failed to merge branch 'remotes/${sub_project}/${branch_name}' from ${sub_project}"
    fi

    # And now see if we need to commit (maybe there was a merge)
    commit_merge "${sub_project}/${branch_name}"

    # relocate projects files into own directory
    if [ "$(ls)" == "${sub_project}" ] ; then
      echo -e "WARN:   Not moving files in branch ${branch_name} of ${sub_project} as already only one root level."
      echo -e "WARN:   Not moving files in branch ${branch_name} of ${sub_project} as already only one root level." >>${LOG_FILE} 2>&1
    else
      echo -e "INFO:   Moving files in branch ${branch_name} of ${sub_project} so we have a single directory..."
      echo -e "INFO:   Moving files in branch ${branch_name} of ${sub_project} so we have a single directory..." >>${LOG_FILE} 2>&1
      mkdir ${sub_project}
      for f in $(ls -a) ; do
        if  [[ "$f" == "${sub_project}" ]] ||
            [[ "$f" == "." ]] ||
            [[ "$f" == ".." ]] ; then
          continue
        fi
        git mv -k "$f" "${sub_project}/"
      done

      # commit the moving
      if ! git commit --quiet -m  "[Project] Move ${sub_project} files into sub directory" ; then
        failed "Failed to commit moving of ${sub_project} files into sub directory"
      fi
    fi
    echo
  done < <(git ls-remote --heads ${sub_project})


  # checkout master of sub probject
  if ! git checkout "${sub_project}/master" >>${LOG_FILE} 2>&1 ; then
    failed "sub_project ${sub_project} is missing master branch!"
  fi

  # copy remote tags
  echo -e "INFO:   Copying tags for ${sub_project}..."
  echo -e "INFO:   Copying tags for ${sub_project}..." >>${LOG_FILE} 2>&1
  while read tag ; do
    tag_ref=$(echo $tag | tr " " "\t" | cut -f 1)
    tag_name_unfixed=$(echo $tag | tr " " "\t" | cut -f 2 | cut -d / -f 3)

    # hack for broken tag names where they are like 1.2.0^{} instead of just 1.2.0
    tag_name="${tag_name_unfixed%%^*}"

    tag_new_name="${sub_project}/${tag_name}"
    echo -e "INFO:     Copying tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}..."
    echo -e "INFO:     Copying tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}..." >>${LOG_FILE} 2>&1
    if ! git tag "${tag_new_name}" "${tag_ref}" >>${LOG_FILE} 2>&1 ; then
      echo -e "WARN:     Could not copy tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}"
      echo -e "WARN:     Could not copy tag ${tag_name_unfixed} to ${tag_new_name} for ref ${tag_ref}" >>${LOG_FILE} 2>&1
    fi
  done < <(git ls-remote --tags --refs ${sub_project})

  # Remove the remote to the old project
  echo -e "INFO:   Removing remote ${sub_project}..."
  echo -e "INFO:   Removing remote ${sub_project}..." >>${LOG_FILE} 2>&1
  git remote rm ${sub_project}

  echo
done


# Now merge all project master branches into new master
git checkout --quiet master
echo -e "INFO: Merging projects master branches into new repository..."
echo -e "INFO: Merging projects master branches into new repository..." >>${LOG_FILE} 2>&1
echo -e "===================================================="
echo -e "====================================================" >>${LOG_FILE} 2>&1
for url in $(cat ${REPO_URL_FILE}) ; do

  if [[ ${url:0:1} == '#' ]] ; then
    continue
  fi

  # extract the name of this project
  export sub_project=${url##*/}
  sub_project=${sub_project%*.git}

  echo -e "INFO:   Merging ${sub_project}..."
  echo -e "INFO:   Merging ${sub_project}..." >>${LOG_FILE} 2>&1
  if ! git merge --allow-unrelated-histories --no-commit "${sub_project}/master" >>${LOG_FILE} 2>&1 ; then
    failed "Failed to merge branch ${sub_project}/master into master"
  fi

  # And now see if we need to commit (maybe there was a merge)
  commit_merge "${sub_project}/master"

  echo
done


# Done
cd ${ROOT_DIR}
echo -e "INFO: Done."
echo -e "INFO: Done." >>${LOG_FILE} 2>&1
echo

exit 0

Sie können es auch von http://paste.ubuntu.com/11732805 erhalten

Erstellen Sie zunächst eine Datei mit der URL zu jedem Repository, z.

git@github.com:eitchnet/ch.eitchnet.parent.git
git@github.com:eitchnet/ch.eitchnet.utils.git
git@github.com:eitchnet/ch.eitchnet.privilege.git

Rufen Sie dann das Skript mit einem Namen des Projekts und dem Pfad zum Skript auf:

./mergeGitRepositories.sh eitchnet_test eitchnet.lst

Das Skript selbst enthält viele Kommentare, die erklären sollten, was es tut.


Anstatt die Leser auf eine Antwort hinzuweisen, posten Sie die Antwort bitte hier (auch bekannt als "Bearbeiten", was Sie in diesem Kommentar gesagt haben, in dieser Antwort).
Josliber

1
Klar, dachte nur, es wäre besser, mich nicht zu wiederholen ... =)
eitch

Wenn Sie der Meinung sind, dass diese Frage mit der anderen identisch ist, können Sie sie als Duplikat kennzeichnen, indem Sie den Link "Flag" unter der Frage selbst verwenden und die andere Frage angeben. Wenn es sich nicht um eine doppelte Frage handelt, Sie jedoch der Meinung sind, dass zur Lösung beider Probleme genau dieselbe Antwort verwendet werden kann, senden Sie einfach dieselbe Antwort auf beide Probleme (wie Sie es jetzt getan haben). Vielen Dank für Ihren Beitrag!
Josliber

Tolle! Funktionierte nicht mit der Windows-Bash-Eingabeaufforderung, lief jedoch einwandfrei von einer Vagrant-Box aus, auf der Ubuntu ausgeführt wird. Was für eine Zeitersparnis!
xverges


7

Ich weiß, dass es lange nach der Tat ist, aber ich war mit den anderen Antworten, die ich hier gefunden habe, nicht zufrieden, also schrieb ich Folgendes:

me=$(basename $0)

TMP=$(mktemp -d /tmp/$me.XXXXXXXX)
echo 
echo "building new repo in $TMP"
echo
sleep 1

set -e

cd $TMP
mkdir new-repo
cd new-repo
    git init
    cd ..

x=0
while [ -n "$1" ]; do
    repo="$1"; shift
    git clone "$repo"
    dirname=$(basename $repo | sed -e 's/\s/-/g')
    if [[ $dirname =~ ^git:.*\.git$ ]]; then
        dirname=$(echo $dirname | sed s/.git$//)
    fi

    cd $dirname
        git remote rm origin
        git filter-branch --tree-filter \
            "(mkdir -p $dirname; find . -maxdepth 1 ! -name . ! -name .git ! -name $dirname -exec mv {} $dirname/ \;)"
        cd ..

    cd new-repo
        git pull --no-commit ../$dirname
        [ $x -gt 0 ] && git commit -m "merge made by $me"
        cd ..

    x=$(( x + 1 ))
done

2
Genau das habe ich gesucht. Vielen Dank! Allerdings musste ich Zeile 22 ändern zu:if [[ $dirname =~ ^.*\.git$ ]]; then
Heyman

2
^. * blarg $ ist verschwenderisch gierig RE. Sagen Sie besser .blarg $ und überspringen Sie den vorderen Anker.
Jettero

7

Wenn Sie versuchen, einfach zwei Repositorys zusammenzukleben, sind Submodule und Zusammenführungen von Teilbäumen das falsche Werkzeug, da sie nicht den gesamten Dateiversionsverlauf beibehalten (wie in anderen Antworten angegeben). In dieser Antwort finden Sie die einfache und korrekte Vorgehensweise.


1
Ihre Lösung funktioniert nur für neue Repositorys. Wie wäre es jedoch, Repo mit Dateikonflikten in einem anderen zusammenzuführen?
Andrey Izman

6

Ich hatte eine ähnliche Herausforderung, aber in meinem Fall hatten wir eine Version der Codebasis in Repo A entwickelt und diese dann in ein neues Repo, Repo B, für die neue Version des Produkts geklont. Nachdem wir einige Fehler in Repo A behoben hatten, mussten wir die Änderungen in Repo B korrigieren. Am Ende haben wir Folgendes getan:

  1. Hinzufügen einer Fernbedienung zu Repo B, die auf Repo A zeigt (git remote add ...)
  2. Ziehen des aktuellen Zweigs (wir haben Master nicht für Fehlerkorrekturen verwendet) (Git Pull RemoteForRepoA BugFixBranch)
  3. Pushing verschmilzt zu Github

Arbeitete ein Vergnügen :)


5

Ähnlich wie @Smar, verwendet jedoch Dateisystempfade, die in PRIMARY und SECONDARY festgelegt sind:

PRIMARY=~/Code/project1
SECONDARY=~/Code/project2
cd $PRIMARY
git remote add test $SECONDARY && git fetch test
git merge test/master

Dann führen Sie manuell zusammen.

(angepasst von Post von Anar Manafov )


5

Zusammenführen von 2 Repos

git clone ssh://<project-repo> project1
cd project1
git remote add -f project2 project2
git merge --allow-unrelated-histories project2/master
git remote rm project2

delete the ref to avoid errors
git update-ref -d refs/remotes/project2/master

4

Wenn Sie drei oder mehr Projekte in einem einzigen Commit zusammenführen möchten , führen Sie die in den anderen Antworten ( remote add -f, merge) beschriebenen Schritte aus . Setzen Sie dann (weich) den Index auf den alten Kopf zurück (wo keine Zusammenführung stattgefunden hat). Fügen Sie alle Dateien hinzu ( git add -A) und schreiben Sie sie fest (Meldung "Projekte A, B, C und D zu einem Projekt zusammenführen). Dies ist jetzt die Festschreibungs-ID des Masters.

Erstellen Sie nun .git/info/graftsmit folgendem Inhalt:

<commit-id of master> <list of commit ids of all parents>

Ausführen git filter-branch -- head^..head head^2..head head^3..head. Wenn Sie mehr als drei Zweige haben, fügen head^n..headSie einfach so viel hinzu, wie Sie Zweige haben. Zum Aktualisieren von Tags anhängen --tag-name-filter cat. Fügen Sie dies nicht immer hinzu, da dies zu einem Umschreiben einiger Commits führen kann. Einzelheiten finden Sie in der Manpage des Filterzweigs , suchen Sie nach "Transplantaten".

Jetzt sind Ihrem letzten Commit die richtigen Eltern zugeordnet.


1
Warten Sie, warum sollten Sie drei Projekte in einem einzigen Commit zusammenführen?
Steve Bennett

Ich habe mit Repository, Repository-Client und Modellierer als separate Git-Projekte begonnen. Das war für die Mitarbeiter schwierig, deshalb habe ich mich ihnen in einem einzigen Git-Projekt angeschlossen. Um zu können, dass die "Wurzel" des neuen Projekts aus drei anderen Projekten stammt, wollte ich ein Single Merge Commit.
Koppor

4

So fügen Sie ein A in B zusammen:

1) Im Projekt A.

git fast-export --all --date-order > /tmp/ProjectAExport

2) Im Projekt B.

git checkout -b projectA
git fast-import --force < /tmp/ProjectAExport

Führen Sie in diesem Zweig alle erforderlichen Vorgänge aus und legen Sie sie fest.

C) Dann zurück zum Meister und eine klassische Verschmelzung zwischen den beiden Zweigen:

git checkout master
git merge projectA

2

Diese Funktion klont das Remote-Repo in das lokale Repo-Verzeichnis. Nach dem Zusammenführen werden alle Commits gespeichert und git logdie ursprünglichen Commits und die richtigen Pfade angezeigt:

function git-add-repo
{
    repo="$1"
    dir="$(echo "$2" | sed 's/\/$//')"
    path="$(pwd)"

    tmp="$(mktemp -d)"
    remote="$(echo "$tmp" | sed 's/\///g'| sed 's/\./_/g')"

    git clone "$repo" "$tmp"
    cd "$tmp"

    git filter-branch --index-filter '
        git ls-files -s |
        sed "s,\t,&'"$dir"'/," |
        GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
        mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
    ' HEAD

    cd "$path"
    git remote add -f "$remote" "file://$tmp/.git"
    git pull "$remote/master"
    git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master"
    git remote remove "$remote"
    rm -rf "$tmp"
}

Wie benutzt man:

cd current/package
git-add-repo https://github.com/example/example dir/to/save

Wenn Sie ein wenig Änderungen vornehmen, können Sie sogar Dateien / Verzeichnisse von zusammengeführtem Repo in verschiedene Pfade verschieben, zum Beispiel:

repo="https://github.com/example/example"
path="$(pwd)"

tmp="$(mktemp -d)"
remote="$(echo "$tmp" | sed 's/\///g' | sed 's/\./_/g')"

git clone "$repo" "$tmp"
cd "$tmp"

GIT_ADD_STORED=""

function git-mv-store
{
    from="$(echo "$1" | sed 's/\./\\./')"
    to="$(echo "$2" | sed 's/\./\\./')"

    GIT_ADD_STORED+='s,\t'"$from"',\t'"$to"',;'
}

# NOTICE! This paths used for example! Use yours instead!
git-mv-store 'public/index.php' 'public/admin.php'
git-mv-store 'public/data' 'public/x/_data'
git-mv-store 'public/.htaccess' '.htaccess'
git-mv-store 'core/config' 'config/config'
git-mv-store 'core/defines.php' 'defines/defines.php'
git-mv-store 'README.md' 'doc/README.md'
git-mv-store '.gitignore' 'unneeded/.gitignore'

git filter-branch --index-filter '
    git ls-files -s |
    sed "'"$GIT_ADD_STORED"'" |
    GIT_INDEX_FILE="$GIT_INDEX_FILE.new" git update-index --index-info &&
    mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"
' HEAD

GIT_ADD_STORED=""

cd "$path"
git remote add -f "$remote" "file://$tmp/.git"
git pull "$remote/master"
git merge --allow-unrelated-histories -m "Merge repo $repo into master" --edit "$remote/master"
git remote remove "$remote"
rm -rf "$tmp"

Hinweise
Pfade werden über ersetzt. sedStellen Sie daher sicher, dass sie nach dem Zusammenführen in den richtigen Pfaden verschoben wurden.
Der --allow-unrelated-historiesParameter existiert nur seit git> = 2.9.


1

Ein gegebener Befehl ist die bestmögliche Lösung, die ich vorschlage.

git subtree add --prefix=MY_PROJECT git://github.com/project/my_project.git master

1

Ich füge Projekte leicht manuell zusammen, wodurch ich vermeiden muss, mich mit Zusammenführungskonflikten befassen zu müssen.

Kopieren Sie zunächst die Dateien aus dem anderen Projekt, wie Sie möchten.

cp -R myotherproject newdirectory
git add newdirectory

nächster Zug in der Geschichte

git fetch path_or_url_to_other_repo

Sagen Sie git, er soll in der Geschichte des zuletzt abgerufenen Dings verschmelzen

echo 'FETCH_HEAD' > .git/MERGE_HEAD

Jetzt festschreiben, wie Sie es normalerweise tun würden

git commit

0

Ich wollte ein kleines Projekt in ein Unterverzeichnis eines größeren Projekts verschieben. Da mein kleines Projekt nicht viele Commits hatte, habe ich verwendet git format-patch --output-directory /path/to/patch-dir. Dann habe ich bei dem größeren Projekt verwendet git am --directory=dir/in/project /path/to/patch-dir/*.

Das fühlt sich viel weniger beängstigend und viel sauberer an als ein Filterzweig. Zugegeben, es ist möglicherweise nicht in allen Fällen anwendbar.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.