Ce post est la suite de notre article GIT - 1 - la base.
9. Branche
Comme nous l’avons évoqué précédemment, la notion la plus importante de Git est la notion de branche.
Suite à notre dernière commande (git checkout 38db667
), le dépôt n’est plus rattaché à une branche.
Mais nous pouvons en créer une!
C’est ce que nous allons faire avec la commande suivante :
git checkout -b onFirstCommit
A présent nous sommes dans la branche onFirstCommit
.
Git a créé une nouvelle branche dans le dépôt à partir du premier commit présent dans l’historique : 38db667
.
Contrairement à d’autres gestionnaires de source (TFS par exemple), Git ne crée pas un dossier par branche.
Lorsque l’on change de branche, le contenu du dossier est restauré à l’état où il était après le commit courant, ici 38db667
.
Revenez dans la branche main
:
git checkout main
Voici ce que vous devriez avoir à présent :
MINGW64 ~/source/repos/agora/github/mon-premier-repo (main)
$ git lg
* d17c78e - (HEAD -> main) ajout de 2emeFichier.txt et modification de 1erFichier.txt
* 38db667 - (onFirstCommit) creation du dépôt ajout de 1erFichier.txt
10. Head
Dans votre dépôt, vous avez une branche onFirstCommit
et une branche main
.
La mention HEAD (pour tête de lecture cf. cassettes à bandes magnétiques 👴) vous informe sur quelle branche est votre dépôt actuellement :
MINGW64 ~/source/repos/agora/github/mon-premier-repo (main)
$ git lg
* d17c78e - (HEAD -> main) ajout de 2emeFichier.txt et modification de 1erFichier.txt
* 38db667 - (onFirstCommit) creation du dépôt ajout de 1erFichier.txt
Vous êtes dans la branche main
et il existe une autre branche onFirstCommit
.
11. Rebase, Merge, Cherry-Pick
Dans cette partie nous allons apprendre 3 techniques indispensables pour se sortir de presque toutes les situations :
- Rebase,
- Merge,
- et Cherry-Pick.
11.1 Rebase
Cette commande a pour objectif d’appliquer tous les commits d’une branche à une autre depuis le dernier commit commun aux deux branches.
Créez de nouveau une branche :
git checkout -b branchToRebase
Ajoutez un fichier addedOnBranchToRebase
:
touch addedOnBranchToRebase.txt
Effectuez un commit contenant cet ajout de fichier :
git add .
git commit -m "ajout de addedOnBranchToMerge.txt"
Ensuite ajoutez du texte dans ce fichier et faites de nouveau un commit avec cette modification :
git add .
git commit -m "modification de addedOnBranchToRebase.txt"
Voici le résultat :
MINGW64 ~/source/repos/agora/github/mon-premier-repo (branchToRebase)
$ git lg
* d2f1efe - (HEAD -> branchToRebase) modification de addedOnBranchToRebase.txt
* d609c65 - ajout de addedOnBranchToMerge.txt
* d17c78e - (main) ajout de 2emeFichier.txt et modification de 1erFichier.txt
* 38db667 - (onFirstCommit) creation du dépôt ajout de 1erFichier.txt
Repartez dans la branch main
:
git checkout main
Modifiez le fichier 2emeFichier.txt
et effectuez un commit dans main
:
git add .
git commit -m "modification de 2emeFichier.txt"
Utilisez la commande suivante pour voir toutes les branches actuelles :
git lg --branches=*
Vous devez avoir ceci :
MINGW64 ~/source/repos/agora/github/mon-premier-repo (main)
$ git lg --branches=*
* fd34ef1 - (HEAD -> main) modification de 2emeFichier.txt
| * d2f1efe - (branchToRebase) modification de addedOnBranchToRebase.txt
| * d609c65 - ajout de addedOnBranchToMerge.txt (Alex 2 minutes ago)
|/
* d17c78e - ajout de 2emeFichier.txt et modification de 1erFichier.txt
* 38db667 - (onFirstCommit) creation du dépôt ajout de 1erFichier.txt
Nous allons à présent effectuer un rebase de la branche branchToRebase
dans main
:
git rebase branchToRebase
Utilisez de nouveau la commande :
git lg --branches=*
Voici le résultat :
MINGW64 ~/source/repos/agora/github/mon-premier-repo (main)
$ git lg --branches=*
* 9ef588c - (HEAD -> main) modification de 2emeFichier.txt
* d2f1efe - (branchToRebase) modification de addedOnBranchToRebase.txt
* d609c65 - ajout de addedOnBranchToMerge.txt
* d17c78e - ajout de 2emeFichier.txt et modification de 1erFichier.txt
* 38db667 - (onFirstCommit) creation du dépôt ajout de 1erFichier.txt
Git a intégré les commits de branchToRebase
dans main
en partant du dernier commit commun entre les deux branches, puis il a ajouté à la suite (toujours dans main
) les commits qui n’étaient pas dans la branche branchToRebase
.
Voici ce que nous avions avant le rebase :
fd34ef1 (main)
/
...----38db667---d17c78e---d609c65---d2f1efe (branchToRebase)
Voici ce que nous avons après :
fd34ef1 (main)
/
...----38db667---d17c78e---d609c65---d2f1efe (branchToRebase)
main
contient à présent les commits de branchToRebase
plus le commit fd34ef1
qui n’est pas présent dans branchToRebase
11.2 Merge
Merge signifie fusionner.
Comme son nom l’indique cette commande a pour objectif de fusionner l’historique de deux branches en un nouveau commit de fusion.
Créez de nouveau une branche :
git checkout -b branchToMerge
Ajoutez un fichier addedOnBranchToMerge
:
touch addedOnBranchToMerge.txt
Effectuez un commit contenant cet ajout de fichier :
git add .
git commit -m "ajout de addedOnBranchToMerge.txt"
Ensuite ajoutez du texte dans ce fichier et faites de nouveau un commit avec cette modification :
git add .
git commit -m "modification de addedOnBranchToMerge.txt"
Voici le résultat :
MINGW64 ~/source/repos/agora/github/mon-premier-repo (branchToMerge)
$ git lg
* 97115b5 - (HEAD -> branchToMerge) modification de addedOnBranchToMerge.txt
* c55aecb - ajout de addedOnBranchToMerge.txt
* 9ef588c - (main) modification de 2emeFichier.txt
* d2f1efe - (branchToRebase) modification de addedOnBranchToRebase.txt
* d609c65 - ajout de addedOnBranchToMerge.txt
* d17c78e - ajout de 2emeFichier.txt et modification de 1erFichier.txt
* 38db667 - (onFirstCommit) creation du dépôt ajout de 1erFichier.txt
Repartez dans la branch main
.
git checkout main
Modifiez le fichier 2emeFichier.txt et effectuez un commit dans main
git add .
git commit -m "2ème modification de 2emeFichier.txt"
Utilisez la commande suivante pour voir toutes les branches actuelles :
git lg --branches=*
Voici l’état des branches :
MINGW64 ~/source/repos/agora/github/mon-premier-repo (main)
$ git lg --branches=*
* 2805653 - (HEAD -> main) 2ème modification de 2emeFichier.txt
| * 97115b5 - (branchToMerge) modification de addedOnBranchToMerge.txt
| * c55aecb - ajout de addedOnBranchToMerge.txt
|/
* 9ef588c - modification de 2emeFichier.txt
* d2f1efe - (branchToRebase) modification de addedOnBranchToRebase.txt
* d609c65 - ajout de addedOnBranchToMerge.txt
* d17c78e - ajout de 2emeFichier.txt et modification de 1erFichier.txt
* 38db667 - (onFirstCommit) creation du dépôt ajout de 1erFichier.txt
Nous allons effectuer un merge de la branche branchToMerge
dans main
:
git merge branchToMerge
Voici l’état des branches après merge:
MINGW64 ~/source/repos/agora/github/mon-premier-repo (main)
$ git lg --branches=*
* cc665a6 - (HEAD -> main) Merge branch 'branchToMerge'
|\
| * 97115b5 - (branchToMerge) modification de addedOnBranchToMerge.txt
| * c55aecb - ajout de addedOnBranchToMerge.txt
* | 2805653 - 2ème modification de 2emeFichier.txt
|/
* 9ef588c - modification de 2emeFichier.txt
* d2f1efe - (branchToRebase) modification de addedOnBranchToRebase.txt
* d609c65 - ajout de addedOnBranchToMerge.txt
* d17c78e - ajout de 2emeFichier.txt et modification de 1erFichier.txt
* 38db667 - (onFirstCommit) creation du dépôt ajout de 1erFichier.txt
Git a intégré les modifications de branchToMerge
dans main
créant un nouveau commit de fusion contenant toutes les modifications des commits qui n’étaient pas dans la branche main.
Voici ce que nous avions avant le merge :
c55aecb---97115b5 (branchToMerge)
/
...---d2f1efe---9ef588c---2805653 (main)
Voici ce que nous avons après :
c55aecb---97115b5 (branchToMerge)
/ \
...---d2f1efe---9ef588c---2805653---cc665a6 (main)
11.3 Cherry-Pick
Cherry-pick signifie cueillir les cerises.
Cette commande permet de récupérer n’importe quel commit dans la branche courante.
Elle vous permettra de vous sortir de pas mal de situations compliquées.
Pour tester cette commande, ajoutez un fichier nommé cherryToPick.txt
dans la branche main
puis effectuez un commit :
touch cherryToPick.txt
git add .
git commit -m "ajout de cherryToPick.txt"
Vous devez obtenir cela à présent :
MINGW64 ~/source/repos/agora/github/mon-premier-repo (main)
$ git lg
* cbc6bfa - (HEAD -> main) ajout de cherryToPick.txt
* cc665a6 - Merge branch 'branchToMerge'
|\
| * 97115b5 - (branchToMerge) modification de addedOnBranchToMerge.txt
| * c55aecb - ajout de addedOnBranchToMerge.txt
* | 2805653 - 2ème modification de 2emeFichier.txt
|/
* 9ef588c - modification de 2emeFichier.txt
* d2f1efe - (branchToRebase) modification de addedOnBranchToRebase.txt
* d609c65 - ajout de addedOnBranchToMerge.txt
* d17c78e - ajout de 2emeFichier.txt et modification de 1erFichier.txt
* 38db667 - (onFirstCommit) creation du dépôt ajout de 1erFichier.txt
Ensuite allez sur la branche onFirstCommit
:
git checkout onFirstCommit
Et tapez la commande :
git cherry-pick cbc6bfa
Vous avez récupéré le commit cbc6bfa
dans votre branche courante et les modifications associées :
MINGW64 ~/source/repos/agora/github/mon-premier-repo (onFirstCommit)
$ git lg
* 40bcc78 - (HEAD -> onFirstCommit) ajout de cherryToPick.txt (Alex 2 minutes ago)
* 38db667 - creation du dépôt ajout de 1erFichier.txt (Alex 49 minutes ago)
Mais son numéro de commit est différent : 40bcc78
!
Voici ce que nous avions avant le Cherry Pick :
d17c78e---...---cc665a6---cbc6bfa (main)
/
38db667 (onFirstCommit)
Voici ce que nous avons après :
d17c78e---...---cc665a6---cbc6bfa (main)
/
38db667---40bcc78 (onFirstCommit)
12 Les conflits
Nous avons vu comment effectuer des Rebases, des Merges et des Cherrys Picks.
Les cas présentés précédemment sont simples.
En pratique, lorsqu’on travaille sur plusieurs branches, il est fréquent de tomber sur des conflits.
Un conflit survient lorsque par exemple deux développeurs modifient le même contenu dans deux branches distinctes.
Nous allons en créer un volontairement!
Pour cela modifiez le fichier 1erFichier.txt
dans la branche actuelle (onFirstCommit
) et effectuez ensuite un commit sur cette branche :
git add .
git commit -m "modification de 1erFichier.txt sur onFirstCommit"
Voici le résultat :
MINGW64 ~/source/repos/agora/github/mon-premier-repo (onFirstCommit)
$ git lg --branches=*
* 55452a6 - (HEAD -> onFirstCommit) modification de 1erFichier.txt sur onFirstCommit
* 40bcc78 - ajout de cherryToPick.txt
| * cbc6bfa - (main) ajout de cherryToPick.txt
| * cc665a6 - Merge branch 'branchToMerge'
| |\
| | * 97115b5 - (branchToMerge) modification de addedOnBranchToMerge.txt
| | * c55aecb - ajout de addedOnBranchToMerge.txt
| * | 2805653 - 2ème modification de 2emeFichier.txt
| |/
| * 9ef588c - modification de 2emeFichier.txt
| * d2f1efe - (branchToRebase) modification de addedOnBranchToRebase.txt
| * d609c65 - ajout de addedOnBranchToMerge.txt
| * d17c78e - ajout de 2emeFichier.txt et modification de 1erFichier.txt
|/
* 38db667 - creation du dépôt ajout de 1erFichier.txt
Dans notre exemple les commits d17c78e - ajout de 2emeFichier.txt et modification de 1erFichier.txt
et 55452a6 - modification de 1erFichier.txt sur onFirstCommit
vont entrer en conflit car nous avons modifié le fichier 1erFichier.txt
au moment endroit (la première ligne)!
Effectuez un rebase de la branche main
pour provoquer le conflit :
git rebase main
Ensuite allez dans le fichier 1erFichier.txt :
<<<<<< HEAD (Current Change)
première modification
=======
ceci va créer un conflit
>>>>>> 55452a6 (modification de 1erFichier.txt sur onFirstCommit) (Incoming Change)
Le Current Change est une modification contenue dans un commit provenant de la branche que nous sommes en train de “rebaser” dans notre branche courante.
Effectuez un git status
MINGW64 ~/source/repos/agora/github/mon-premier-repo (onFirstCommit|REBASE 1/1)
$ git status
interactive rebase in progress; onto cbc6bfa
Last command done (1 command done):
pick 55452a6 modification de 1erFichier.txt sur onFirstCommit
No commands remaining.
You are currently rebasing branch 'onFirstCommit' on 'cbc6bfa'.
(fix conflicts and then run "git rebase --continue")
(use "git rebase --skip" to skip this patch)
(use "git rebase --abort" to check out the original branch)
Unmerged paths:
(use "git restore --staged <file>..." to unstage)
(use "git add <file>..." to mark resolution)
both modified: 1erFichier.txt
no changes added to commit (use "git add" and/or "git commit -a")
Nous avons notre premier conflit à résoudre!
Il est possible de le résoudre manuellement.
Pour cela :
- supprimez ‘««« HEAD’, ‘=======’ et ‘»»» 55452a6’.
- gardez le texte que vous souhaitez conserver.
- sauvegardez le fichier
Et utilisez ensuite les commandes suivantes :
git add .
git rebase --continue
Voici le résultat suite à la résolution du conflit :
MINGW64 ~/source/repos/agora/github/mon-premier-repo (onFirstCommit)
$ git lg
* 160c615 - (HEAD -> onFirstCommit) modification de 1erFichier.txt sur onFirstCommit
* cbc6bfa - (main) ajout de cherryToPick.txt
* cc665a6 - Merge branch 'branchToMerge'
|\
| * 97115b5 - (branchToMerge) modification de addedOnBranchToMerge.txt
| * c55aecb - ajout de addedOnBranchToMerge.txt
* | 2805653 - 2ème modification de 2emeFichier.txt
|/
* 9ef588c - modification de 2emeFichier.txt
* d2f1efe - (branchToRebase) modification de addedOnBranchToRebase.txt
* d609c65 - ajout de addedOnBranchToMerge.txt
* d17c78e - ajout de 2emeFichier.txt et modification de 1erFichier.txt
* 38db667 - creation du dépôt ajout de 1erFichier.txt
A présent votre branche contient tous les commits de la branche main
et le commit qui posait problème 55452a6 modification de 1erFichier.txt sur onFirstCommit
a été modifié en 160c615 modification de 1erFichier.txt sur onFirstCommit
pour prendre en compte votre résolution de conflit!
La suite
Bon tout ça c’est très bien mais dans l’introduction de cette série d’article nous avions parlé de travailler en équipe et pour l’instant on travaille seul et en local… Nous allons donc voir comment échanger du code avec d’autres développeurs dans notre prochain post sur Git : 3 - les dépôts Git!