Fusionner deux dépôts git
12 Jul 2017Ce billet explique comment fusionner un dépôt git (avec son historique) dans un sous-répertoire d’un autre dépôt git.
Cas d’usage
Mon projet principal se trouve dans un dépôt main
. J’ai démarré dans un autre
dépôt un projet other
, que je souhaite finalement intégrer dans un
sous-répertoire sub/
du projet principal, en conservant son historique. Après
cette fusion, je ne garderai que le dépôt principal.
Fusion
Les deux projets se trouvent dans le répertoire courant :
$ ls
main other
Dans le dépôt main
, copier la branche master
de other
dans une nouvelle
branche tmp
:
cd main
git fetch ../other master:tmp
Le dépôt main
contient alors les historiques disjoints des deux projets.
Nous allons maintenant réécrire l’historique complet de la branche tmp
pour
déplacer tout le contenu dans un sous-répertoire sub/
, grâce une commande
donnée en exemple de man git filter-branch
:
git checkout tmp
git filter-branch --index-filter \
'git ls-files -s | sed "s-\t\"*-&sub/-" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"'
À ce stade, nous avons toujours deux historiques indépendants, mais le contenu
lié à la branche tmp
se trouve dans le sous-répertoire sub/
.
A---B---C---D master
X---Y---Z tmp
La dernière étape consiste à relier les deux historiques, soit grâce à un rebase, soit grâce à un merge.
Un rebase réécrit l’historique du sous-projet sur la branche master
:
git rebase master
# A---B---C---D---X'--Y'--Z' master
Un merge relie juste les deux historiques grâce à un commit de merge :
git merge tmp --allow-unrelated-histories
# A---B---C---D---M master
# /
# X---Y---Z tmp
Concrètement
J’ai débuté la réécriture du serveur relais de gnirehtet en Rust dans un dépôt séparé. Maintenant qu’il commence à fonctionner, je l’ai fusionné dans un sous-répertoire du dépôt principal tout en conservant l’historique :
git fetch ../rustrelay master:tmp
git checkout tmp
git filter-branch --index-filter \
'git ls-files -s | sed "s-\t\"*-&rustrelay/-" |
GIT_INDEX_FILE=$GIT_INDEX_FILE.new \
git update-index --index-info &&
mv "$GIT_INDEX_FILE.new" "$GIT_INDEX_FILE"'
git rebase master
Super merci, j’étais justement en train de chercher comment faire, j’ai maintenant ma réponse :)