2281 Stimmen

Wie führt man zwei Git-Repositories zusammen?

Stellen Sie sich das folgende Szenario vor:

Ich habe ein kleines experimentelles Projekt A in einem eigenen Git Repo entwickelt. Jetzt ist es ausgereift, und ich möchte, dass A Teil des größeren Projekts B ist, das sein eigenes großes Repository hat. Ich möchte nun A als Unterverzeichnis von B hinzufügen.

Wie kann ich A mit B verschmelzen, ohne dass die Geschichte auf irgendeiner Seite verloren geht?

17 Stimmen

Wenn Sie nur versuchen, zwei Repositories zu einem einzigen zusammenzufassen, ohne beide Repositories behalten zu müssen, werfen Sie einen Blick auf diese Frage: stackoverflow.com/questions/13040958/

0 Stimmen

Für das Zusammenführen von Git Repo in einem benutzerdefinierten Verzeichnis mit Speicherung aller Comits verwenden Sie stackoverflow.com/a/43340714/1772410

2894voto

Andresch Serj Punkte 31645

Wenn Sie Folgendes zusammenführen möchten project-a en 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 sehr gut funktioniert, sie ist kürzer und meiner Meinung nach viel sauberer.

Für den Fall, dass Sie die project-a in ein Unterverzeichnis, können Sie mit git-filter-repo ( filter-branch es entmutigt ). 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 2 großen Repositories, wobei eines davon in ein Unterverzeichnis gelegt wird: https://gist.github.com/x-yuri/9890ab1079cf4357d6f269d073fd9731

Nota: Die --allow-unrelated-histories gibt es erst seit git >= 2.9. Siehe Git - git merge Dokumentation / --allow-unrelated-histories

Update : Hinzugefügt --tags wie von @jstadler vorgeschlagen, um die Tags zu behalten.

2 Stimmen

Es scheint, dass eine funktionierende Kopie benötigt wird: fatal: This operation must be run in a work tree Ich möchte zwei nackte Git-Repositorien zusammenführen.

2 Stimmen

@LiuYan: Sry das kommt ein bisschen spät, aber Sie könnten eine Arbeitskopie erstellen, indem Sie eines der Projekte auschecken und dann wie beschrieben vorgehen.

2 Stimmen

Beachten Sie, dass dadurch keine Untermodule zusammengeführt werden.

663voto

Jakub Narębski Punkte 286531

Hier sind zwei mögliche Lösungen:

Untermodule

Kopieren Sie entweder das Repository A in ein separates Verzeichnis im größeren Projekt B, oder (vielleicht besser) klonen Sie das Repository A in ein Unterverzeichnis im Projekt B. Dann verwenden Sie Git-Submodul um dieses Repository zu einem Submodul 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. SubmoduleSupport et GitSubmoduleTutorial Seiten auf Git Wiki.

Zusammenführung von Teilbäumen

Sie können das Repository A in ein Unterverzeichnis eines Projekts B einbinden, indem Sie die Teilbaum-Zusammenführung Strategie. Diese wird beschrieben in Teilbaum-Zusammenführung und Sie von Markus Prinz.

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

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

Oder Sie können verwenden Git-Teilbaum Werkzeug ( Repository auf GitHub ) von apenwarr (Avery Pennarun), angekündigt zum Beispiel in seinem Blogbeitrag Eine neue Alternative zu Git-Submodulen: git subtree .


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

0 Stimmen

Ich habe alles gefunden, was ich brauchte, um mein lokales Repository in ein Unterverzeichnis eines entfernten Repositorys zu legen, indem ich dem HOWTO "how to use the subtree merge strategy" folgte.

0 Stimmen

Hmm 'git pull -s subtree Bproject master' aktualisiert den Tag Bproject/master in der Historie nicht auf den neuen Bproject HEAD

1 Stimmen

Dies funktioniert und scheint den Verlauf zu bewahren, aber nicht so, dass man damit Dateien vergleichen oder die Zusammenführung halbieren könnte. Übersehe ich einen Schritt?

520voto

Simon Perepelitsa Punkte 19921

Ein einzelner Zweig eines anderen Repositorys kann einfach in ein Unterverzeichnis gelegt werden, das seine Geschichte beibehält. Zum Beispiel:

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

Dies erscheint als ein einzelner Commit, bei dem alle Dateien des Rails-Masterzweigs in das Verzeichnis "rails" hinzugefügt werden. Der Commit-Titel enthält jedoch einen Verweis auf den alten Historienbaum:

Hinzufügen von 'rails/' von commit <rev>

Wo <rev> ist ein SHA-1-Commit-Hash. Sie können immer noch die Historie sehen, einige Änderungen tadeln.

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

Beachten Sie, dass Sie das Verzeichnispräfix von hier aus nicht sehen können, da es sich um einen alten, intakten Zweig handelt. Sie sollten dies wie eine gewöhnliche Dateiverschiebung behandeln: Sie werden einen zusätzlichen Sprung benötigen, 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 z. B. die manuelle Durchführung oder das Umschreiben des Verlaufs, wie in anderen Antworten beschrieben.

Der Befehl git-subtree ist ein Teil der offiziellen git-contrib, einige Paketmanager installieren ihn standardmäßig (OS X Homebrew). Sie müssen ihn aber möglicherweise selbst zusätzlich zu git installieren.

3 Stimmen

Hier finden Sie Anweisungen zur Installation von Git SubTree (Stand: Juni 2013): stackoverflow.com/a/11613541/694469 (und ich ersetzte git co v1.7.11.3 con ... v1.8.3 ).

1 Stimmen

Vielen Dank für den Hinweis auf die unten stehende Antwort. Ab Git 1.8.4 ist "subtree" immer noch nicht enthalten (zumindest nicht auf der Ubuntu 12.04 git ppa (ppa:git-core/ppa) )

1 Stimmen

Das kann ich bestätigen, git log rails/somefile zeigt die Commit-Historie dieser Datei nicht an, außer dem Merge-Commit. Wie @artfulrobot vorgeschlagen hat, prüfen Sie Die Antwort von Greg Hewgill . Und möglicherweise müssen Sie git filter-branch auf dem Repository, das Sie einbinden möchten.

213voto

Greg Hewgill Punkte 882617

Der Submodul-Ansatz ist gut, wenn Sie das Projekt separat pflegen wollen. Wenn Sie jedoch beide Projekte in ein gemeinsames Repository zusammenführen möchten, müssen Sie etwas mehr Arbeit leisten.

Der erste Schritt wäre die Verwendung von git filter-branch um die Namen aller Dateien im zweiten Repository so umzuschreiben, dass sie sich in dem Unterverzeichnis befinden, in dem sie gespeichert werden sollen. Also statt foo.c , bar.html würden Sie projb/foo.c et projb/bar.html .

Dann sollten Sie in der Lage sein, etwas wie das Folgende zu tun:

git remote add projb [wherever]
git pull projb

El git pull wird eine git fetch gefolgt von einer git merge . Es sollte keine Konflikte geben, wenn das Repository, in das Sie ziehen, noch keine projb/ Verzeichnis.

Weitere Recherchen ergaben, dass etwas Ähnliches auch bei der Zusammenlegung von gitk en git . Junio C. Hamano schreibt hier darüber: http://www.mail-archive.com/git@vger.kernel.org/msg03395.html

1 Stimmen

Da ich dies nicht selbst ausprobiert habe, ist die git pull Schritt kann sich darüber beschweren, dass kein gemeinsamer Vorfahre gefunden werden kann. Auch einige andere Details müssen möglicherweise noch geklärt werden.

4 Stimmen

Die Zusammenführung von Teilbäumen wäre die bessere Lösung und erfordert kein Umschreiben der Geschichte des einbezogenen Projekts.

9 Stimmen

Ich würde gerne wissen, wie man git filter-branch um dies zu erreichen. In der Manpage steht das Gegenteil: subdir/ wird zum Root, aber nicht andersherum.

82voto

Paul Draper Punkte 70845

git-subtree ist nett, aber wahrscheinlich nicht das, was Sie wollen.

Zum Beispiel, wenn projectA ist das in B erstellte Verzeichnis, nachdem git subtree ,

git log projectA

Listen nur einer commit: die Zusammenführung. Die Commits aus dem zusammengeführten Projekt sind für andere Pfade, daher werden sie nicht angezeigt.

Die Antwort von Greg Hewgill kommt dem am nächsten, auch wenn sie nicht genau sagt, wie man die Pfade umschreibt.


Die Lösung ist verblüffend 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 die Historie neu geschrieben; Sie sollten daher zunächst eine Sicherungskopie von A erstellen.

Hinweis Bene: Sie müssen das Ersatzskript innerhalb des sed-Befehls ändern, wenn Sie Nicht-Ascii-Zeichen (oder weiße Zeichen) in Dateinamen oder Pfaden verwenden. In diesem Fall beginnt der Dateispeicherort innerhalb eines von "ls-files -s" erzeugten Datensatzes mit Anführungszeichen.

(2) Dann führen Sie in B

git pull path/to/A

Voilà! Sie haben eine projectA Verzeichnis in B. Wenn Sie git log projectA sehen Sie alle Übertragungen von A.


In meinem Fall wollte ich zwei Unterverzeichnisse, projectA et projectB . In diesem Fall habe ich Schritt (1) auch für B durchgeführt.

1 Stimmen

Es sieht so aus, als hätten Sie Ihre Antwort von stackoverflow.com/a/618113/586086 ?

1 Stimmen

@AndrewMao, ich glaube schon... Ich kann mich nicht mehr erinnern. Ich habe dieses Skript ziemlich oft benutzt.

1 Stimmen

Das Original ist unter git-scm.com/docs/git-filter-branch Die andere Frage knüpft daran an. Es ist eine interessante, wenn auch verwirrende Lektüre.

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