99 votes

Fusionner le dépôt git dans un sous-répertoire

Je voudrais fusionner un dépôt git distant dans mon dépôt git de travail comme un sous-répertoire de celui-ci. J'aimerais que le dépôt résultant contienne l'historique fusionné des deux dépôts et aussi que chaque fichier du dépôt fusionné conserve son historique tel qu'il était dans le dépôt distant. J'ai essayé d'utiliser la stratégie de sous-arborescence telle que mentionnée dans le document Comment utiliser la stratégie de fusion de sous-arbres ? Mais après avoir suivi cette procédure, bien que le dépôt résultant contienne effectivement l'historique fusionné des deux dépôts, les fichiers individuels provenant du dépôt distant n'ont pas conservé leur historique (`git log' sur l'un d'entre eux montre juste un message "Merged branch...").

Je ne veux pas non plus utiliser de submodules car je ne veux plus que les deux dépôts git combinés soient séparés.

Est-il possible de fusionner un dépôt git distant dans un autre en tant que sous-répertoire, les fichiers individuels provenant du dépôt distant conservant leur historique ?

Merci beaucoup pour toute aide.

EDIT : J'essaie actuellement une solution qui utilise git filter-branch pour réécrire l'historique du dépôt fusionné. Cela semble fonctionner, mais je dois la tester un peu plus. Je reviendrai pour faire un rapport sur mes découvertes.

EDIT 2 : Dans l'espoir d'être plus clair, je donne les commandes exactes que j'ai utilisées avec la stratégie de sous-arbres de git, qui ont pour résultat une perte apparente de l'historique des fichiers du dépôt distant. Soit A le dépôt git dans lequel je travaille actuellement et B le dépôt git que je voudrais incorporer dans A en tant que sous-répertoire de celui-ci. Il a fait ce qui suit :

git remote add -f B <url-of-B>
git merge -s ours --no-commit B/master
git read-tree --prefix=subdir/Iwant/to/put/B/in/ -u B/master
git commit -m "Merge B as subdirectory in subdir/Iwant/to/put/B/in."

Après ces commandes et en allant dans le répertoire subdir/Iwant/to/put/B/in, je vois tous les fichiers de B, mais git log sur l'un d'entre eux ne montre que le message de livraison "Merge B as subdirectory in subdir/Iwant/to/put/B/in". L'historique de leurs fichiers tel qu'il est dans B est perdu.

Quoi semble pour fonctionner (comme je suis un débutant sur git, je peux me tromper) est la suivante :

git remote add -f B <url-of-B>
git checkout -b B_branch B/master  # make a local branch following B's master
git filter-branch --index-filter \ 
   'git ls-files -s | sed "s-\t\"*-&subdir/Iwant/to/put/B/in/-" |
        GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
                git update-index --index-info &&
        mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD 
git checkout master
git merge B_branch

La commande ci-dessus pour filter-branch est tirée de git help filter-branch dans lequel je n'ai changé que le chemin du sous-répertoire.

0 votes

Qu'est-ce que gitk dire sur l'histoire ? J'ai utilisé git subtree merge avec succès dans le passé. Peut-être pouvez-vous révéler vos commandes exactes ? Je ne suis pas sûr que git-filter-branch soit la bonne approche. Je pourrais recommander d'essayer git-fast-export et git-fast-import pour synthétiser un nouvel historique.

0 votes

Après avoir effectué la procédure de sous-arbre gitk montre les deux dépôts fusionnés sur leurs pointes et non liés dans leurs commits initiaux. (Cela aiderait-il si je postais des captures d'écran de la vue historique de gitk ? Puis-je ?) Malheureusement, les fichiers individuels du dépôt distant n'ont pas conservé leur historique si je fais dans le terminal git log <file-from-remote-repo> . Je regarde dans git-fast-export y git-fast-import Je suis très novice en matière de git. Je vais modifier ma question pour montrer exactement les commandes que j'ai utilisées avec git subtree. Merci beaucoup pour votre réponse.

0 votes

@christosc : votre deuxième méthode a fonctionné à merveille et très simplement, merci beaucoup ! J'ai juste dû changer subdirir/Iwant/en/put/B/in/ et en faire un oneliner (parce que msysgit sous Windows ne semble pas supporter les retours à la ligne dans les commandes avec ) : git filter-branch --index-filter 'git ls-files -s | sed "s- \t\ "*-&subdir/Iwant/to/put/B/in/-" | GIT_INDEX_FILE=$GIT_INDEX_FILE.new git update-index --index-info && mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"' HEAD

4voto

0__ Points 23597

J'ai trouvé la solution suivante qui me convient. D'abord, je vais dans le projet B, je crée une nouvelle branche dans laquelle tous les fichiers seront déjà déplacés vers le nouveau sous-répertoire. Je pousse ensuite cette nouvelle branche vers l'origine. Ensuite, je vais dans le projet A, j'ajoute et récupère le remote de B, puis je vérifie la branche déplacée, je retourne dans master et je fusionne :

# in local copy of project B
git checkout -b prepare_move
mkdir subdir
git mv <files_to_move> subdir/
git commit -m 'move files to subdir'
git push origin prepare_move

# in local copy of project A
git remote add -f B_origin <remote-url>
git checkout -b from_B B_origin/prepare_move
git checkout master
git merge from_B

Si je vais dans le sous-répertoire subdir je peux utiliser git log --follow et avoir encore l'histoire.

Je ne suis pas un expert de git, je ne peux donc pas dire si cette solution est particulièrement bonne ou si elle présente des inconvénients, mais jusqu'à présent, tout semble bien fonctionner.

0 votes

Les gens semblent approuver cette approche ici : stackoverflow.com/questions/1683531/

3voto

Stuck Points 2206

Similaire à celui de hfs réponse Je voulais

  • conserver une histoire linéaire sans fusion explicite et
  • donne l'impression que les fichiers du dépôt fusionné ont toujours existé dans le sous-répertoire, et par effet secondaire, fait en sorte que git log -- file travailler sans --follow .

Cependant, j'ai choisi le plus moderne filter-repo (en supposant que le new existe et est extrait) :

git clone git@host/repo/old.git
cd old
git checkout -b tmp_subdir
git filter-repo --to-subdirectory-filter old

cd ../new
git remote add old ../old
git fetch old
git rebase --rebase-merges --onto main --root old/tmp_subdir --committer-date-is-author-date

vous devrez peut-être résoudre les conflits (manuellement) ou modifier la commande rebase pour inclure --merge -s recursive -X theirs si vous voulez essayer de le résoudre avec theirs version :

git rebase --rebase-merges --onto main --root old/tmp_subdir --committer-
date-is-author-date --merge -s recursive -X theirs

vous vous retrouvez sur un HEAD détaché, donc créez une nouvelle branche et fusionnez-la avec main Notez que les dépôts modernes ne devraient pas utiliser une branche "master" mais une branche "main".

branch for a more inclusive language.
git checkout -b old_merge
git checkout main
git merge old_merge

nettoyage

git branch -d old_merge
git remote rm old

2voto

Abizern Points 52378

Avez-vous essayé d'ajouter le dépôt supplémentaire comme un submodule git ? Cela ne fusionnera pas l'historique avec le dépôt contenant, en fait, ce sera un dépôt indépendant.

Je le mentionne, parce que vous ne l'avez pas fait.

2 votes

Merci pour la réponse Abizern. En fait, je veux que les deux historiques de dépôt soient fusionnés en un seul ; je ne veux plus qu'ils soient séparés, c'est pourquoi je n'ai pas mentionné les submodules.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X