Question Comment fusionnez-vous deux référentiels Git?


Considérez le scénario suivant:

J'ai développé un petit projet expérimental A dans son propre repo Git. Il a maintenant mûri, et j'aimerais que A fasse partie du plus grand projet B, qui a son propre grand dépôt. Je voudrais maintenant ajouter A comme un sous-répertoire de B.

Comment puis-je fusionner A en B, sans perdre l'histoire de quelque côté que ce soit?


1220
2017-09-15 08:31


origine


Réponses:


Une seule branche d'un autre référentiel peut être facilement placée sous un sous-répertoire en conservant son historique. Par exemple:

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

Cela apparaîtra comme une seule validation où tous les fichiers de la branche principale de Rails sont ajoutés dans le répertoire "rails". Cependant, le titre du commit contient une référence à l'ancien historique:

Ajouter 'rails /' du commit <rev>

<rev> est un hash de commit SHA-1. Vous pouvez toujours voir l'histoire, blâmer certains changements.

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

Notez que vous ne pouvez pas voir le préfixe du répertoire d'ici, car il s'agit d'une ancienne branche intacte. Vous devriez traiter cela comme un commit de déplacement de fichier habituel: vous aurez besoin d'un saut supplémentaire pour l'atteindre.

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

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

Il existe des solutions plus complexes comme le faire manuellement ou réécrire l'histoire comme décrit dans d'autres réponses.

La commande git-subtree fait partie du git-contrib officiel, certains gestionnaires de paquets l'installent par défaut (OS X Homebrew). Mais vous devrez peut-être l'installer par vous-même en plus de git.


326
2018-02-20 23:44



Si vous voulez fusionner project-a dans project-b:

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

Pris à partir de: git fusionner différents dépôts?

Cette méthode a plutôt bien fonctionné pour moi, elle est plus courte et à mon avis beaucoup plus propre.

Remarque: le --allow-unrelated-histories Ce paramètre n'existe que depuis git> = 2.9. Voir Git-git fusionne la documentation / --allow-unrelated-histories 


1279
2018-05-11 09:37



Voici deux solutions possibles:

Sous-modules

Copiez le référentiel A dans un répertoire séparé dans le projet B plus grand, ou (peut-être mieux) dans le répertoire A du sous-répertoire clone du projet B. Ensuite, utilisez git sous-module pour faire de ce dépôt un sous-module d'un référentiel B.

C'est une bonne solution pour les dépôts à couplage lâche, où le développement dans le référentiel A se poursuit, et la majeure partie du développement est un développement autonome séparé en A. Voir aussi Sous-moduleSupport et GitSubmoduleTutorial pages sur Git Wiki.

Fusion de sous-arbres

Vous pouvez fusionner le référentiel A dans un sous-répertoire d'un projet B en utilisant fusion de sous-arbres stratégie. Ceci est décrit dans Subtree fusion et vous par 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 est nécessaire pour git> = 2.9.0)

Ou vous pouvez utiliser git sous-arbre outil (référentiel sur github) par Apenwarr (Avery Pennarun), annoncé par exemple dans son blog Une nouvelle alternative aux sous-modules git: git subtree.


Je pense que dans votre cas (A doit faire partie du plus grand projet B) la bonne solution serait d'utiliser fusion de sous-arbres


581
2017-09-15 08:38



L'approche sous-module est bonne si vous voulez maintenir le projet séparément. Cependant, si vous voulez vraiment fusionner les deux projets dans le même référentiel, alors vous avez un peu plus de travail à faire.

La première chose serait d'utiliser git filter-branch pour réécrire les noms de tout dans le deuxième référentiel à être dans le sous-répertoire où vous souhaitez qu'ils finissent. Donc, au lieu de foo.c, bar.html, tu aurais projb/foo.c et projb/bar.html.

Ensuite, vous devriez être capable de faire quelque chose comme:

git remote add projb [wherever]
git pull projb

le git pull fera un git fetch suivi d'un git merge. Il ne devrait pas y avoir de conflits, si le référentiel que vous utilisez n'a pas encore de projb/ annuaire.

Une recherche plus poussée indique que quelque chose de similaire a été fait pour fusionner gitk dans git. Junio ​​C Hamano écrit à ce sujet ici: http://www.mail-archive.com/git@vger.kernel.org/msg03395.html


187
2018-02-01 08:10



git-subtree c'est bien, mais ce n'est probablement pas celui que vous voulez.

Par exemple, si projectA est le répertoire créé en B, après git subtree,

git log projectA

listes seulement un commit: la fusion. Les validations du projet fusionné concernent des chemins différents, de sorte qu'elles n'apparaissent pas.

La réponse de Greg Hewgill est la plus proche, même si elle ne dit pas vraiment comment réécrire les chemins.


La solution est étonnamment simple.

(1) En 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

Remarque: Ceci réécrit l'historique, donc si vous avez l'intention de continuer à utiliser ce repo A, vous voudrez peut-être cloner (copier) une copie jetable en premier.

(2) Ensuite, en B, lancez

git pull path/to/A

Voila! Tu as un projectA répertoire dans B. Si vous exécutez git log projectA, vous verrez tous les commits de A.


Dans mon cas, je voulais deux sous-répertoires, projectA et projectB. Dans ce cas, j'ai fait l'étape (1) à B aussi.


62
2018-06-11 14:31



Si les deux référentiels ont le même type de fichiers (comme deux référentiels Rails pour différents projets), vous pouvez extraire les données du référentiel secondaire vers votre référentiel actuel:

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

puis fusionnez-le au référentiel actuel:

git merge --allow-unrelated-histories branch_name

Si votre version de Git est inférieure à 2,9, supprimez --allow-unrelated-histories.

Après cela, des conflits peuvent se produire. Vous pouvez les résoudre par exemple avec git mergetool. kdiff3 peut être utilisé uniquement avec le clavier, donc 5 fichier de conflit prend en lisant le code quelques minutes.

N'oubliez pas de terminer la fusion:

git commit

39
2018-02-27 03:09



J'ai continué à perdre de l'historique en utilisant la fusion, donc j'ai fini par utiliser rebase puisque dans mon cas les deux dépôts sont assez différents pour ne pas finir par fusionner à chaque commit:

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

=> résoudre les conflits, puis continuer, autant de fois que nécessaire ...

git rebase --continue

Cela conduit à un projet ayant tous les commits de projA suivi de commits de projB


19
2017-08-18 21:06