Skip to content

Latest commit

 

History

History
103 lines (84 loc) · 5.62 KB

subtree-merges.asc

File metadata and controls

103 lines (84 loc) · 5.62 KB
Subtree Merging

L’idée de la fusion de sous-arbre est que vous avez deux projets, et l’un des projets se réfère à un sous-dossier de l’autre et vice-versa. Quand vous spécifiez une fusion de sous-arbre, Git est souvent assez malin pour se rendre compte que l’un est un sous-arbre de l’autre et fusionner comme il faut.

Nous allons explorer à travers un exemple comment ajouter un projet séparé à l’intérieur d’un projet existant et ensuite fusionner le code du second dans un sous-dossier du premier.

D’abord, nous ajouterons l’application Rack à notre projet. Nous ajouterons le projet Rack en tant que référence distante dans notre propre projet puis l’extrairons dans sa propre branche :

$ git remote add rack_remote https://github.com/rack/rack
$ git fetch rack_remote
warning: no common commits
remote: Counting objects: 3184, done.
remote: Compressing objects: 100% (1465/1465), done.
remote: Total 3184 (delta 1952), reused 2770 (delta 1675)
Receiving objects: 100% (3184/3184), 677.42 KiB | 4 KiB/s, done.
Resolving deltas: 100% (1952/1952), done.
From https://github.com/rack/rack
 * [new branch]      build      -> rack_remote/build
 * [new branch]      master     -> rack_remote/master
 * [new branch]      rack-0.4   -> rack_remote/rack-0.4
 * [new branch]      rack-0.9   -> rack_remote/rack-0.9
$ git checkout -b rack_branch rack_remote/master
Branch rack_branch set up to track remote branch refs/remotes/rack_remote/master.
Switched to a new branch "rack_branch"

Maintenant nous avons la racine du projet Rack dans notre branche rack_branch et notre propre projet dans la branche master. Si vous extrayez un projet puis l’autre, vous verrez qu’ils ont des racines de projet différentes :

$ ls
AUTHORS         KNOWN-ISSUES   Rakefile      contrib         lib
COPYING         README         bin           example         test
$ git checkout master
Switched to branch "master"
$ ls
README

C’est un concept assez étrange. Toutes les branches de votre dépôt n’ont pas vraiment besoin d’être des branches du même projet. C’est inhabituel, parce que c’est rarement utile, mais c’est assez facile d’avoir des branches qui contiennent des historiques totalement différents.

Dans notre cas, nous voulons tirer le projet Rack dans notre projet master en tant que sous-dossier. Nous pouvons faire cela dans Git avec la commande git read-tree. Vous en apprendrez plus sur read-tree et ses amis dans ch10-git-internals.asc, mais pour l’instant sachez qu’elle lit l’arborescence d’une branche dans votre index courant et dans le répertoire de travail. Nous venons de rebasculer dans notre branche master, et nous tirons la branche rack_branch dans le sous-dossier rack de notre branche master de notre projet principal :

$ git read-tree --prefix=rack/ -u rack_branch

Quand nous validons, c’est comme si nous avions tous les fichiers Rack dans ce sous-dossier – comme si les avions copiés depuis une archive. Ce qui est intéressant est que nous pouvons assez facilement fusionner les modifications d’une des branches dans l’autre. Donc, si le projet Rack est mis à jour, nous pouvons tirer en amont les modifications en basculant sur cette branche et en tirant :

$ git checkout rack_branch
$ git pull

Ensuite, nous pouvons fusionner les modifications dans notre brancher master. Nous pouvons utiliser git merge -s subtree et cela marchera bien, mais Git fusionnera lui aussi les historiques ensemble, ce que nous ne voudrons probablement pas. Pour tirer les modifications et préremplir le message de validation, utilisez les options --squash et --no-commit en complément de l’option de stratégie -s subtree :

$ git checkout master
$ git merge --squash -s subtree --no-commit rack_branch
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested

Toutes les modifications du projet Rach sont fusionnées et prêtes à être validées localement. Vous pouvez aussi faire l’inverse – faire les modifications dans le sous-dossier rack de votre branche master et ensuite les fusionner plus tard dans votre branche rack_branch pour les soumettre aux mainteneurs ou les pousser en amont.

Ceci nous donne un moyen d’avoir un flux de travail quelque peu similaire au flux de travail des sous-modules sans utiliser les sous-modules (que nous couvrirons dans ch07-git-tools.asc). Nous pouvons garder dans notre dépôt des branches avec d’autres projets liés et les fusionner façon sous-arbre dans notre projet occasionnellement. C’est bien par certains côtés ; par exemple tout le code est validé à un seul endroit. Cependant, cela a d’autres défauts comme le fait que c’est un petit peu plus complexe et c’est plus facile de faire des erreurs en réintégrant les modifications ou en poussant accidentellement une branche dans un dépôt qui n’a rien à voir.

Une autre chose un peu étrange est que pour obtenir la différence entre ce que vous avez dans votre sous-dossier rack et le code dans votre branche rack_branch – pour voir si vous avez besoin de les fusionner – vous ne pouvez pas utiliser la commande diff classique. À la place, vous devez lancer git diff-tree avec la branche que vous voulez comparer :

$ git diff-tree -p rack_branch

Ou, pour comparer ce qui est dans votre sous-dossier rack avec ce qu’était la branche master sur le serveur la dernière fois que vous avez tiré, vous pouvez lancer

$ git diff-tree -p rack_remote/master