®om's blog { un blog libre }

Fusionner deux dépôts git

Ce 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

Commentaires

Super merci, j’étais justement en train de chercher comment faire, j’ai maintenant ma réponse :)

Poster un commentaire

Nom : (requis)
E-mail : (optionnel, non publié)
Site web : (optionnel)
Quelle est la 3e lettre du mot blog ? (antispam)

Les commentaires sont formatés en markdown.