Fusionner des branches

Nous avons vu ce que sont les branches Git. Nous allons maintenant présenter pourquoi fusionner des branches et comment s’y prendre.

Mise en place

Pour cette partie nous créons un dépôt distant sur notre Gitlab (comme expliqué dans la partie 1), puis nous le clonons sur notre machine locale.

$ git clone https://gitlab.com/chaica/merge-branches.git
Cloning into 'merge-branches'…
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
$ cd merge-branches/
$ ls
README.md

Notre dépôt initial contient simplement un fichier README.md, créé par Gitlab, contenant un titre en langage Markdown

$ cat README.md
# merge-branch

Nous allons maintenant ajouter un sous-titre à ce fichier pour un prochain exemple.

$ echo -e "\n## sous-titre" >> README.md
$ git commit README.md -m "add first subtitle"
[master 2059805] add first subtitle
 1 file changed, 2 insertions(+)

À ce niveau, nous avons donc deux commits qui constituent notre branche master, comme nous l’indique la commande git log.

$ git log
commit 20598053fb2c3e55f95e2521dfa804739abd7d8a
Author: Carl Chenet chaica@ohmytux.com
Date:   Fri Jun 21 10:22:00 2019 +0200

 add first subtitle

commit 11cb68a24bed5236972138a1211d189adb4512a8 (origin/master, origin/HEAD)
Author: Carl Chenet chaica@ohmytux.com
Date:   Fri Jun 21 08:18:56 2019 +0000

 Initial commit

Mise en place un peu longue, mais qui nous a permis de réviser quelques commandes fondamentales. Nous entrons dans le vif du sujet.

Création d’une nouvelle branche

Un client nous demande une évolution du code. Afin de ne pas toucher à la branche master qui contient le code de référence courant, nous allons compliquer maintenant un peu les choses en créant une nouvelle branche nommée branch-with-foo. Cette étape a déjà été expliquée dans la partie 4 plus en détail.

$ git checkout -b branch-with-foo
Switched to a new branch 'branch-with-foo'

Nous créons immédiatement un fichier nommé foo dans cette branche que nous ajoutons et enregistrons dans la foulée.

$ echo "this is a foo file" > foo
$ git add foo && git commit foo -m "add foo file"
[branch-with-foo d9afaa2] add foo file
 1 file changed, 1 insertion(+)
 create mode 100644 foo

Divergence des branches

Nous revenons maintenant sur master et nous créons un fichier bar que nous enregistrons aussi dans la foulée.

$ git checkout master
$ echo "this is a bar file" > bar
$ git add bar && git commit bar -m "add bar file"
[master 222c618] add bar file
 1 file changed, 1 insertion(+)
 create mode 100644 bar

Faisons une pause, nous venons de créer notre première divergence entre nos branches, nous avons créé un embranchement dans l’historique de nos commits, les deux derniers commits n’appartenant plus aux mêmes branches.

all branches

Le schéma présente la divergence entre la branche master et la branche branch-with-foo. La première contient un fichier bar, la seconde un fichier foo. Bien, il est temps de passer aux choses sérieuses.

Fuuuuuuuuuusion

Le besoin que nous avions de créer une nouvelle branche a disparu, le client a annulé le projet.

Bon, nous allons réintégrer les modifications de cette branche dans la branche master. Nous nous positionnons dans la branche master, ou d’une manière générale la branche à laquelle nous souhaitons réintégrer les modifications d’une autre, et nous passons la commande suivante :

$ git checkout master
$ git merge branch-with-foo -m "Merge branch 'branch-with-foo'"
Merge made by the 'recursive' strategy.
  foo | 1 +
  1 file changed, 1 insertion(+)
  create mode 100644 foo

La sortie de la commande nous précise ce qui s’est passé : un fichier foo (celui de la branche branch-with-foo) a été créé dans la branche courante master.

fusion

Jetons un oeil à l’historique avec la commande git log avec l’option --graph qui va nous présenter une représentation graphique de notre historique et l’option --oneline afin de rendre la commande moins verbeuse.

$ git log --graph --oneline
* 69fa060 (HEAD -> master) Merge branch 'branch-with-foo'
|\
| * d9afaa2 (branch-with-foo) add foo file
* |222c618 add bar file
|/
* 2059805 add first subtitle
* 11cb68a (origin/master, origin/HEAD) Initial commit

Cette représentation est très parlante. Au niveau de l’histoire elle va de haut en bas, le haut étant le commit le plus récent et le plus bas le plus vieux. Une étoile (*) est un commit, avec son message à droite , et le nom de la branche s’il y ambiguité.

Nous reprenons notre dessin précédent et le faisons évoluer.

after merge

Nous avons bien fusionné la branche branch-with-foo dans master. Fusion réussie.

Sauver son code et ses branches

Avant de s’arrêter aujourd’hui, n’oublions pas de pousser tout ce que nous avons fait vers notre dépôt Gitlab distant. Nous commençons par la branche master.

$ git push
Enumerating objects: 13, done.
Counting objects: 100% (13/13), done.
Delta compression using up to 8 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (11/11), 975 bytes | 975.00 KiB/s, done.
Total 11 (delta 2), reused 0 (delta 0)
To https://gitlab.com/chaica/merge-branches.git
   11cb68a..69fa060  master -> master

La dernière ligne indique bien que nous avons poussé depuis notre branche master locale vers notre branche master distante présent sur notre Gitlab.

Passons à la branche branch-with-foo, qui, même si elle a été fusionnée dans master, existe toujours. Pourquoi ? Car le nom de la branche branch-with-foo est un pointeur, un indicateur qui désigne le dernier commit connu de cette branche. Rien de plus.

Pour changer un peu nous varions la syntaxe de notre commande git push en utilisant l’option --all afin de pousser toutes les branches locales vers le dépot distant. Nous n’en avons qu’une ici, branch-with-foo.

$ git push --all
Total 0 (delta 0), reused 0 (delta 0)
remote:
remote: To create a merge request for branch-with-foo, visit:
remote:   https://gitlab.com/chaica/merge-branches/merge_requests/new?merge_request%5Bsource_branch%5D=branch-with-foo
remote:
To https://gitlab.com/chaica/merge-branches.git
[new branch]      branch-with-foo -> branch-with-foo

Point très intéressant, nous voyons que les lignes commençant par remote: proviennent du Gitlab, qui nous indiquent comment créer une demande de fusion (Merge Request). Inutile, nous avons déjà fusionné. Mais ce sera intéressant dans le cadre du travail collaboratif. Ce sera pour un prochain article.

gitlab mr

La dernière ligne nous confirme que nous avons bien poussé la branche locale branch-with-foo vers la branche du dépôt Gitlab distant nommée également branch-with-foo.

Conclusion

Nous avons vu aujourd’hui la fusion de branches Git. Cette opération permet de récupérer le travail réalisé dans une autre branche, en divergence du code “principal” que nous conservons – comme bonne pratique dans l’industrie en général – dans la branche master. C’est le cas le plus courant.

Vous devriez quasi systématiquement commencer par créer une nouvelle branche quand vous envisagez d’introduire du nouveau code dans un dépôt Git, afin de ne pas travailler directement vous-même dans master. Pourquoi pas ? C’est ce que nous verrons dans le prochain article de cette série.