Voici le vingt-huitième volet de la formation Git. Dans mon précédent article, nous avons vu comment nous pouvons récupérer la travail effectué par un collègue sur sa propre branche. Cette manipulation nous permet de faire quelque chose d’inédit : modifier le travail d’un collaborateur sur sa propre branche. Voyons en détail les implications pratiques de cette façon de travailler.
Les cuistots et la sauce
Vous connaissez sans doute le fameux proverbe qui dit que trop de cuistots gâtent la sauce. La raison d’être de Git consiste justement à éviter ce genre de désordre. Continuons donc notre démonstration pratique des précédents articles :
$ cd formation-git/atelier-37/ $ ls -l total 12 drwxrwxr-x. 3 kikinovak kikinovak 4096 Apr 7 09:38 clone-de-charles drwxrwxr-x. 3 kikinovak kikinovak 4096 Apr 7 09:53 clone-de-paul drwxrwxr-x. 3 kikinovak kikinovak 4096 Apr 7 08:10 clone-de-stephane $ cd clone-de-charles/
Stéphane a demandé un coup de main à Charles. Il est en mal d’inspiration pour son poème Renouveau et aimerait bien que Charles lui fasse une suggestion sous forme d’un deuxième quatrain. Charles va donc jeter un œil :
$ git switch renouveau Switched to branch 'renouveau' Your branch is up to date with 'origin/renouveau'. $ cat Renouveau.md # Renouveau *Stéphane Mallarmé* Le printemps maladif a chassé tristement L’hiver, saison de l’art serein, l’hiver lucide, Et, dans mon être à qui le sang morne préside L’impuissance s’étire en un long bâillement.
Charles va éditer le fichier Renouveau.md
et ajouter un deuxième quatrain :
Des crépuscules blancs tiédissent sous mon crâne Qu’un cercle de fer serre ainsi qu’un vieux tombeau Et triste, j’erre après un rêve vague et beau, Par les champs où la sève immense se pavane.
Il ajoute le fichier à l’index et effectue un commit :
$ git add Renouveau.md $ git commit -m "Renouveau: 2ème strophe."
Où en sommes-nous maintenant ? Adoptez le réflexe d’utiliser la commande git status
lorsque vous vous posez cette question :
$ git status On branch renouveau Your branch is ahead of 'origin/renouveau' by 1 commit. (use "git push" to publish your local commits)
En langage tam-tam, cela signifie que la branche locale renouveau
est « en avance » d’un commit par rapport à la branche de suivi à distance origin/renouveau
. Là comme ailleurs, les suggestions de Git s’avèrent pertinentes, et il suffit d’un git push
bien senti pour être à jour :
$ git push
Notez ici que Git « sait » que la branche locale renouveau
dispose d’une branche de suivi distant correspondante origin/renouveau
.
À présent, Stéphane peut songer à récupérer le travail de Charles. Voyons à quoi cela ressemble concrètement.
$ cd ../clone-de-stephane/ $ git status On branch renouveau Your branch is up to date with 'origin/renouveau'.
Un détail important : Git ne nous dit pas s’il y a du nouveau dans le dépôt public. C’est là un choix de conception du logiciel. Et très concrètement, c’est aux collaborateurs d’un projet d’aller vérifier de leur côté s’il y a du nouveau :
$ git fetch remote: Enumerating objects: 12, done. remote: Counting objects: 100% (12/12), done. remote: Compressing objects: 100% (9/9), done. remote: Total 9 (delta 1), reused 8 (delta 0), pack-reused 0 Unpacking objects: 100% (9/9), 1.37 KiB | 1.38 MiB/s, done. From github.com:kikinovak/poesie-symboliste 45cb7ce..69736f3 renouveau -> origin/renouveau * [new branch] aurore -> origin/aurore * [new branch] voyage -> origin/voyage
Peu importe la branche sur laquelle vous vous trouvez, git fetch
va récupérer les nouveautés de toutes les branches de suivi à distance.
Stéphane se trouve bien sur la branche renouveau
:
$ git branch
main
* renouveau
Comment se fait-il alors que pour l’instant, il ne voie pas les modifications apportées par Charles ?
$ cat Renouveau.md # Renouveau *Stéphane Mallarmé* Le printemps maladif a chassé tristement L’hiver, saison de l’art serein, l’hiver lucide, Et, dans mon être à qui le sang morne préside L’impuissance s’étire en un long bâillement.
La réponse à cela est simple et nous sert de base pour comprendre le workflow spécifique à Git :
$ git status On branch renouveau Your branch is behind 'origin/renouveau' by 1 commit, and can be fast-forwarded. (use "git pull" to update your local branch)
Pour une fois, nous allons faire fi de la suggestion de Git qui consisterait à invoquer git pull
. Regardons plutôt ce qu’il nous dit une ligne plus haut. Your branch is behind 'origin/renouveau' by 1 commit, and can be fast-forwarded
. En d’autres termes, nous pouvons effectuer un fast-forward merge avec la branche origin/renouveau
:
$ git merge origin/renouveau Updating 45cb7ce..69736f3 Fast-forward Renouveau.md | 5 +++++ 1 file changed, 5 insertions(+)
Cette fois-ci, les modifications apportées par Charles ont bien été récupérées dans le clone de Stéphane :
$ cat Renouveau.md # Renouveau *Stéphane Mallarmé* Le printemps maladif a chassé tristement L’hiver, saison de l’art serein, l’hiver lucide, Et, dans mon être à qui le sang morne préside L’impuissance s’étire en un long bâillement. Des crépuscules blancs tiédissent sous mon crâne Qu’un cercle de fer serre ainsi qu’un vieux tombeau Et triste, j’erre après un rêve vague et beau, Par les champs où la sève immense se pavane.
Pourquoi s’agit-il d’un fast-forward merge ? Tout simplement parce que les deux branches renouveau
et origin/renouveau
n’ont pas divergé depuis que Charles a ajouté une strophe.
Imaginons maintenant un autre cas de figure, où la fusion se complique un tout petit peu. Paul travaille sur son clone local, toujours sur la branche aurore
:
$ cd ../clone-de-paul/ $ git switch aurore Switched to branch 'aurore' Your branch is up to date with 'origin/aurore'.
Avant de continuer à travailler sur Aurore, il a l’idée de faire en parallèle une parodie de soi-même. Il crée un fichier Aurore-Parodie.md
et l’édite comme ceci :
# Aurore (parodie) La félicité sans bornes De ronfler en ton giron Se dissipe dès la morne Apparence des klaxons. Dans mon âme je recule, Toutes mes idées se bousculent ; C'est la première livraison ! À peine sorti des vapes, Je me lève et je dérape Sur le fil du téléphon.
Note du blogueur : cette parodie est de mon cru. En 1995 je m’étais inscrit à un cours terriblement ennuyeux sur Paul Valéry à la Fac de Lettres de Montpellier. Vu que les smartphones n’existaient pas encore à l’époque, je me suis amusé à ma façon.
Paul ajoute le fichier à l’index et effectue un commit :
$ git add Aurore-Parodie.md $ git commit -m "Aurore: Parodie."
Il publie ces modifications :
$ git push
C’est au tour de Charles. Il veut bien filer un autre coup de main à Paul, mais avant de faire quoi que ce soit, il va d’abord vérifier s’il y a du nouveau :
$ cd ../clone-de-charles/ $ git switch aurore Switched to branch 'aurore' Your branch is up to date with 'origin/aurore'. $ git fetch remote: Enumerating objects: 4, done. remote: Counting objects: 100% (4/4), done. remote: Compressing objects: 100% (3/3), done. remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0 Unpacking objects: 100% (3/3), 508 bytes | 508.00 KiB/s, done. From github.com:kikinovak/poesie-symboliste 44d5975..a449645 aurore -> origin/aurore $ git status On branch aurore Your branch is behind 'origin/aurore' by 1 commit, and can be fast-forwarded. (use "git pull" to update your local branch)
Il y a du nouveau sur la branche origin/aurore
. Il va donc fusionner cette branche :
$ git merge origin/aurore Updating 44d5975..a449645 Fast-forward Aurore-Parodie.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 Aurore-Parodie.md
Charles voit apparaître la nouvelle version du poème :
$ ls Aurore.md Aurore-Parodie.md README.md
Cette version n’est pas vraiment à son goût, et il préfère ajouter une strophe au poème original dans le fichier Aurore.md
:
Salut ! encore endormies À vos sourires jumeaux, Similitudes amies Qui brillez parmi les mots ! Au vacarme des abeilles Je vous aurai par corbeilles, Et sur l’échelon tremblant De mon échelle dorée, Ma prudence évaporée Déjà pose son pied blanc.
Il ajoute cette modification à l’index et effectue un commit :
$ git add Aurore.md $ git commit -m "Aurore: 2ème strophe."
Il publie cette suggestion :
$ git push
Pendant que Charles est occupé à faire tout ça, Paul continue à travailler sur son clone local :
$ cd ../clone-de-paul/
Il se dit qu’il a oublié de signer la parodie. Il ouvre le fichier Aurore-Parodie.md
et ajoute l’auteur :
# Aurore (parodie)
*Kiki Novak*
La félicité sans bornes
De ronfler en ton giron
Se dissipe dès la morne
Apparence des klaxons.
Dans mon âme je recule,
Toutes mes idées se bousculent ;
C'est la première livraison !
À peine sorti des vapes,
Je me lève et je dérape
Sur le fil du téléphon.
Il enregistre les modifications et effectue un commit :
$ git add Aurore-Parodie.md $ git commit -m "Aurore (parodie): ajout de l'auteur."
Malheureusement, la tentative de publication avec git push
se solde par un échec :
$ git push To github.com:kikinovak/poesie-symboliste.git ! [rejected] aurore -> aurore (fetch first) error: failed to push some refs to 'github.com:kikinovak/poesie-symboliste.git' hint: Updates were rejected because the remote contains work that you do hint: not have locally. This is usually caused by another repository pushing hint: to the same ref. You may want to first integrate the remote changes hint: (e.g., 'git pull ...') before pushing again. hint: See the 'Note about fast-forwards' in 'git push --help' for details.
Une solution propre consiste ici à récupérer dans un premier temps les nouveautés dans les branches de suivi à distance sans pour autant perturber les branches locales :
$ git fetch remote: Enumerating objects: 10, done. remote: Counting objects: 100% (10/10), done. remote: Compressing objects: 100% (6/6), done. remote: Total 6 (delta 0), reused 6 (delta 0), pack-reused 0 Unpacking objects: 100% (6/6), 1.19 KiB | 1.19 MiB/s, done. From github.com:kikinovak/poesie-symboliste a449645..3b3a59c aurore -> origin/aurore 45cb7ce..69736f3 renouveau -> origin/renouveau
Où en sommes-nous ? Là encore, c’est git status
qui va nous aider à nous repérer :
$ git status On branch aurore Your branch and 'origin/aurore' have diverged, and have 1 and 1 different commits each, respectively.
Paul va tenter de fusionner les deux branches aurore
et origin/aurore
:
$ git merge origin/aurore
Cette fois-ci, Git affiche le message de fusion suivant :
Merge remote-tracking branch 'origin/aurore' into aurore
Que s’est-il passé ? Nous obtenons un merge commit pour la simple raison que les deux branches aurore
et origin/aurore
ont divergé.
Où en sommes-nous maintenant que la fusion a été effectuée avec succès ?
$ git status On branch aurore Your branch is ahead of 'origin/aurore' by 2 commits. (use "git push" to publish your local commits)
Il ne nous reste plus qu’à prendre Git au pied de la lettre et à rendre tout cela public :
$ git push
S’il ne fallait retenir que cela
Dans cet atelier pratique, j’ai mis la charrue de la pratique avant les bœufs de la théorie pour vous faire comprendre par l’exemple que la commande git pull
n’est en somme que la combinaison de git fetch
suivi d’un git merge
. Autrement dit (on insiste un peu là) :
git pull
=git fetch
+git merge
Vous aviez peut-être l’habitude d’utiliser git pull
au quotidien. Le hic ici, c’est que dans certaines situations, beaucoup de choses se passent sous le capot de manière automagique. Le simple fait de remplacer git pull
par la combinaison de git fetch
et git merge
permet de reprendre le contrôle sur tous les détails des opérations, notamment lorsqu’il s’agit de concilier des branches qui divergent un tant soit peu.
Exercice 1
- Complétez petit à petit et strophe par strophe l’anthologie de la poésie symboliste.
- Le texte intégral des trois poèmes est disponible librement sur le web.
- Endossez successivement le rôle de Charles, de Paul et de Stéphane.
- Ne vous découragez pas si vous vous tirez dans le pied.
- Si votre dépôt est dans un piteux état, faites une pause et recommencez le lendemain.
- À un moment, il va falloir intégrer tout ce travail dans la branche principale
main
.
Bonus : un peu de ménage
Une fois que nous avons tout intégré dans la branche main
, il nous reste à faire le ménage dans les branches que nous n’utilisons plus. Vous savez comment supprimer une branche locale :
$ git branch -d aurore Deleted branch aurore (was caaec34).
La suppression d’une branche de suivi distant n’est pas tout à fait intuitive :
$ git push -d origin aurore To github.com:kikinovak/poesie-symboliste.git - [deleted] aurore
La commande git fetch -p
(ou --prune
) permet de faire le ménage dans les branches qui n’ont plus de branche distante correspondante :
$ git fetch -p From github.com:kikinovak/poesie-symboliste - [deleted] (none) -> origin/aurore
La rédaction de cette documentation demande du temps et des quantités significatives de café espresso. Vous appréciez ce blog ? Offrez un café au rédacteur en cliquant sur la tasse.
0 commentaire