La pression de cet article après un bon gros titre putaclic comme ça, j’vous dit pas.

En fin d’études, 2013, j’ai utilisé git pour la première fois.

svn était encore bien accroché, donc la question qui revenait souvent c’était

Quel intérêt par rapport à svn?

tout le monde

Pour le coup… Je n’avais pas su répondre à l’époque.
Étant très habitué à svn j’avais fait l’erreur d’utiliser git comme svn.

De l’eau a coulé sous les ponts et j’ai maintenant beaucoup moins de mal à répondre à cette question.


De mon point de vue, les 2 avantages majeurs sont :
– le mode distribué
– le système de branche

Je ne vais pas parler du mode distribué (ou très très peu).

Le gros sujet ici, c’est le système de branche, un système qui permet de faire tout et n’importe quoi.

Git est un super outil, mais c’est aussi un outil compliqué.
Et comme n’importe quel outil, on ne va pas –forcément– chercher comment il fonctionne tant qu’il fonctionne.

Pire, avec git il y a plein de GUIs qui permettent de ne pas se soucier de ce qui se passe derrière les rideaux…

Les devs qui utilisent sourcetree, gitkraken, etc, sans comprendre les mécaniques derrière.

Pour parer à ce problème, des flows ont été créés.

Le plus populaire était celui là : https://nvie.com/posts/a-successful-git-branching-model/.

Ce n’est pas mal comme flow.

Il implique une gestion de branche correcte, mais il laisse quand même la porte ouverte à un beau bordel.

Et ce n’est pas parce qu’il est mauvais ! Au contraire
Mais bien parce que les devs l’appliquent sans le comprendre !


J’ai un gros problème avec un workflow non maitrisé parcequ’on se retrouve vite avec un arbre en « plan de métro« .

Et même si, parfois, ça peut être utilie, ce n’est généralement pas le cas.

Je sais que mes propos peuvent être difficiles à visualiser, pour cela, je vais vous raconter une histoire…


🤡 C’est l’histoire d’un projet

Bob est en chargé d’un projet.

Il se dit qu’il va utiliser git parce que c’est l’outil à la mode.

Bob ne va pas trop chercher comment tout cela fonctionne… à partir du moment ou cela fonctionne.

NDLR: On considère ici que l’on fera des commits de merge
(donc pas de fast-forward même s’ils sont possibles, git merge –no-ff ).

NDLR2: On considère que Bob et Alice utilisent un dépôt distant de type github, gitlab, bitbucket ou autre.
Ce dépot distant est unique et sera appelé origin.

NDLR3: On considère aussi que les branches ne sont jamais mergées en local, mais tout le temps via le dépôt distant et un principe de pull request / merge request.

NDLR4: Dans les illustrations qui vont suivre, les ronds représentent des commits.
Les étiquettes de couleur, quant à elles, représentent des références, vers des branches par exemple, qu’elles soient locales ou distantes (sur origin).

🥇 First commit

Au début tout se passe bien.
Bob fait le fameux « First commit« , ici bleu.

⤴️ Premières features

Comme Bob n’est pas un sauvage, il va tout de suite partir sur un système de branches pour les features, fix, et autres.

Il crée donc une première branche qui part du commit first commit pour réaliser sa feature verte

Mais Bob veut aller vite.

Il fait donc 2 features sur la même branche, les features verte et orange.

Bob ouvre une pull request pour sa première branche.

Alice fait la review.

Au départ, elle tilte sur le fait qu’il y ait 2 features dans une branche.
Cela prend donc un peu de temps.

Mais après quelques échanges, elle accepte la PR, la branche feat/verte de Bob est mergée dans develop.

Le commit jaune est créée.


🏎 Pas le temps d’niaiser

En attendant qu’Alice vérifie la PR feat/verte dont on parle juste avant, et donc avant que les features verte et orange ne soient mergées, Bob a créé une autre branche pour avancer sur la feature rouge.

Malin ce Bob.

Pour cette branche, il avait besoin d’un tout petit bout de code de la feature verte.
Donc, il est reparti du commit vert et non pas du commit bleu.
(Normal, le commit jaune n’existait pas à l’époque).

Une fois que la feature rouge est finie Bob ouvre une pull request.

Malheureusement, entre temps, Alice avait validé la PR feat/verte.
Cette branche avait donc été mergée et le commit jaune existait… (voir ci-dessous).

Et le problème dans cette histoire, c’est que dans la feature rouge et dans la feature orange Bob a modifié le même fichier, au même endroit.

Cela implique que dans le commit jaune, la modification du fichier vennant du commit orange est présente. Or, dans la PR de Bob pour la feature rouge, on demande à git de modifier le même fichier au même endroit.

On a donc un conflit.

Bon rien de catastrophique, c’est même plutôt courant sur git.

Bob ouvre sa PR, on résout cela dans le commit de merge.
Ce sera le commit violet.


🤝 Alice à la rescousse (ou comment éviter les conflits)

Bob s’est quand même fait remonter les bretelles.

Alice, qui a dû s’occuper de la PR rouge, n’avait aucune envie de résoudre les conflits de Bob.

Alors pour les prochaines fois, Bob est prié de bien vouloir les corriger avant !

« Bien compris » dit-il !

Facile, il me suffit de merger develop dans ma branche, résoudre les conflits et faire une PR par la suite.
Quelle bonne idée.

Grâce à cela, Alice n’aura pas à résoudre les conflits, qui seront résolus dans le commit violet.

Son travail sera de valider la PR depuis le commit violet et cela créera le commit gris.


😏 Oops, un petit fix

NDLR; dans la suite, on utilise sur les mêmes couleurs, mais on ne parle pas des mêmes commits/branches, on va se dire qu’on est quelques temps plus tard.

Les aventures de Bob ne s’arrêtent pas là.

Au cours du projet, une feature verte a été mergée un peu trop vite
(Bob a fait un self-validate de sa PR verte).

Ce qui devait arriver arriva, il a introduit un bug dans develop.

Alice, en pullant develop, l’a remarqué et a tout de suite alerté Bob.

Réactif, Bob est reparti de sa branche verte.

Il a rapidement créé un fix, jaune, ouvert une PR et mergé ce dernier dans develop, créant ainsi le commit rouge pour corriger tout cela.

Ouf.


👿 C’est une urgence pour la démo

Bob, était préssé par Carole la PO / Chef de projet / Scrum Master de son projet.

Elle s’était engagée (oui, elle), auprès du client, il fallait faire la feature rouge pour la déployer avant la démo le lendemain matin.

Comme la dernière fois, il avait besoin d’un bout de vert et n’avait pas le temps d’attendre la validation d’Alice.

En plus quand il a vu qu’il avait créé un bug et qu’il a dû le corriger, il était bien content de ne pas avoir attendu.

Au moins, la feature rouge était prête à temps.


✌️ Player 2 has entered the game

Ainsi s’achèvent (presque) les aventures de Bob au pays de git.

Fort heureusement, il n’était pas seul sur le projet, et avec Alice, ils n’étaient pas peu fiers du travail accompli.

Quant au dépôt git ? Qui s’en soucie vraiment ? À la fin il était plutôt propre non ?

Il ressemblait peut-être à ça ? Ou peut-être pire.

💩 On arrête de faire du sale

Mais alors, comment est-ce que Bob peut éviter tout cela ?

On a identifié plusieurs problèmes:

  • Plusieurs features sur la même branche
  • Avancer sur une feature alors que sa base n’est pas mergée
  • Résoudre un conflit avant le merge
  • Un petit fix ?

Finalement, on veut réécrire l’histoire de ce qui s’est passé.

Ça tombe bien il existe un outil super pour ça: le rebase

NDLR; L’idée ici est de jouer avec l’historique git. Une autre façon de faire est de merger en utilisant la statégie « squash » en fast forward. On n’en parlera pas ici car ce n’est pas le sujet.

🔀 Anatomie d’un rebase (interactif)

Je vais volontairement être réducteur ici, mais, en gros.

Le git rebase c’est un outil qui va permettre de réécrire l’histoire d’une branche.
Pour cela, il va déplacer le commit de départ d’une branche vers un autre commit.

Mais cela ne s’arrête pas là, on peut aller encore plus loin en faisant un rebase interactif !

Cela va nous permettre beaucoup plus de choses:

  • déplacer une branche d’un commit vers un autre commit
  • changer les noms des commits
  • filtrer les commits (en garder certains, en virer d’autres)
  • etc…

Et cela va nous aider pour garder un dépôt propre qui tient plus d’une ligne de TGV que du métro parisien.

Pour faire cela, le rebase va dupliquer les commits de votre branche un a un.
Puis il va supprimer les anciens.

On est donc sur une opération destructrice 💥 et il faut faire attention.

De plus, comme on supprime les commits, les références changent.
Donc git va avoir tendance à être un peu perdu (notemment avec les branches sur vos dépôts distants).

Mais pas de panique, nous sommes des professionnels (et on va voir quelques exemples pour comprendre tout cela)

Comment se passe un rebase ?

On se place sur un commit (ou une branche plus généralement), disons la référence à rebaser.
Ensuite, on définit la référence d’où on veut partir (quel commit ou quelle branche), appelons là référence de départ.
Et pour finir on exécute la commande de rebase

# On se met sur la référence à rebaser
git checkout "reference-à-rebaser"
# On rebase
git rebase -i "reference-de-départ"

Le -i est là pour spécifier qu’on veut un rebase « interactif« .

Grâce à cela, git va faire la liste des commits qu’il y a entre les 2 et nous laisser choisir quoi en faire.

Si cette option n’est pas spécifiée, git va juste prendre tous les commits et les déplacer.

Le fait de spécifier -i ajoute une étape à notre rebase. En effet git va faire la liste et ouvrir votre éditeur par défaut pour vous la présenter.

Par exemple, si on a 3 commits sur notre branche, git affichera cela:

pick 22d839f message du commit 1
pick 3f31c4b message du commit 2
pick 4f2a285 message du commit 3

# Rebase 6d846a1..2b3055d onto 2b3055d (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.

C’est notre responsabilité de décider quoi faire en remplaçant les pick par un des mots-clés expliqués dans commands.


Une fois cela fait, on sauvegarde (généralement, c’est vim qui est utilisé alors on sauvegarde en faisant ESC + :wq + ENTER) et git rebase fait le reste.

Maintenant qu’on a posé les bases, voyons quelques exemples.


🦿 Le cas du multi-feature sur la même branche

Constat de départ

On part de ce constat là:

git checkout -b feat/verte
git commit -m "vert"
git commit -m "orange"
git push origin feat/verte

Bob a donc 2 commits, vert et orange, sur sa branche feat/verte, et origin est à jour sur sa branche (origin/feat/verte est au même niveau que feat/verte)

Or Bob aurait dû la séparer en 2 et faire 2 PR. Une pour la feature verte et une pour orange. Alors comment réparer ça ?

Créer une branche feat/orange

La première étape va être de créer une branche pour orange, appelons là feat/orange.

# Bob se remet sur le commit orange
git checkout "orange"
# Depuis ce commit, Bob créé une nouvelle branche
git checkout -b feat/orange 
# Bob push sa nouvelle branche
git push origin feat/orange

Replacer feat/vert

# Bob se remet sur sa branche feat/vert
git checkout feat/vert
# Bob va forcer la branche "verte" à se remettre sur le commit vert (pour connaitre la sh1, il aura fait un git log --oneline)
git reset --hard "sha1-commit-vert"
# Bob push la branche verte en "forcant" parce que le dépot est en avance
git push -f origin feat/vert

Pourquoi l’option -f pour le git push est nécessaire ici ?

Sur le dépôt distant, la branche verte est en « avance » par rapport à celle locale car sur le commit feat/orange.

Si vous essayez de push, git va le remarquer et refuser le push en vous incitant à pull d’abord pour récupérer les modifications.

Cela est une très mauvaise idée de faire cela.
Ça reviendrait à faire un merge de feat/orange dans feat/vert, ce qui n’est absolument pas ce que l’on veut.

Ce que nous voulons, c’est FORCER feat/vert à se déplacer sur le commit vert, d’où le git push -f.

C’est un bel exemple qui montre que quand on sait comment cela fonctionne on ne doit pas croire tout ce que git nous dit.

Première PR verte

Une fois cela fait, on ouvre la PR verte et Bob attend qu’elle soit validée et mergée.
Il laisse orange tel quel pour l’instant.

Rebaser feat/orange

Maintenant que la PR verte est mergée, Bob va rebaser orange.

# Bob se remet sur sa branche feat/orange
git checkout feat/orange
# Bob va mettre à jour son dépot pour develop (qui contient le commit jaune)
git fetch
# Ensuite il va rebaser sa branche feat/orange sur origin/develop
git rebase -i origin/develop
# Et pusher sa branche
git push -f origin feat/orange

Alors, techniquement qu’est-ce qui s’est passé ici ?

Pour commencer, git a recréé un autre commit orange, il ne l’a pas « déplacé ».

D’ailleurs, c’est pour cela qu’on doit push -f, sinon, sur origin, nous aurons encore l’ancien commit orange, git refusera donc le push en nous disant de récupérer les modifications, comme expliqué précédement.

J’insiste sur le sujet car c’est l’erreur la plus répandue.
Chaque fois que je parle de rebase, on m’explique qu’on a « cassé un dépôt » en l’utilisant et c’est généralement à cause de ça !

Il faut bien comprendre que le contenu des 2 commits est exactement le même ! Donc si on pull, c’est la catastrophe, chaque ligne modifiée est considérée comme un conflit.

Le contenu des 2 commits oranges est exactement le même, mais ce sont bien 2 commits différents.

Donc d’un point de vue git c’est normal qu’il refuse le push !

Pour lui on est à la fois en avance d’un commit (le nouveau orange) et en retard d’un commit (l’ancien orange).

C’est donc parce qu’on sait que l’ancien commit orange ne sert plus à rien qu’on peut l’écraser avec le nouveau avec un git push -f.

Une fois qu’on en est là, techniquement, plus aucune « référence » facile d’accès (comme un tag ou une branche) n’est reliée au commit feature orange original.
D’un certain point de vue il est « perdu » (bon ce n’est pas vraiment le cas, mais c’est une autre histoire)

Une PR et on y va

Partant de là, il ne reste plus qu’à ouvrir une PR et on aura un arbre qui ressemblera à cela


🌪 Avancer sur une feature avec une branche pas mergée

Dans cette situation, finalement, c’est très semblable avec ce qu’on a vu ci-dessus.

Bob a créé une branche feat/rouge depuis feat/verte et a travaillé dessus.

Dans un cas où nous n’avons pas de conflit, on reproduit la méthode vue avant et tout se passe bien

# Bob se met sur sa branche violette
git checkout feat/violet
# Bob se met à jour
git fetch
# Bob rebase sa branche
git rebase -i origin/develop
# Bob push
git push -f origin feat/violet

💥 Le cas d’un conflit

Le problème dans la situation précédente, et nous l’avons vu, c’est si Bob modifie le même fichier dans feat/orange et feat/violet et que cela crée un conflit.

(ce n’est pas toujours le cas, mais pour les besoins de l’article c’est le cas)

Dans cette situation, on pourrait se dire qu’on n’a qu’a merger origin/develop dans notre branche.

Nous aurions quelque chose qui ressemblerait à

Mais c’est exactement ce qu’on veut éviter de faire avec les rebase. On ne va donc pas partir sur cette option !

Dans ce cas, le rebase va nous alerter qu’il y a un conflit et nous demander de le corriger avec un beau message bien explicite.

CONFLICT (add/add): Merge conflict in >>FILE_NAME<<
Auto-merging >>FILE_NAME<<
error: could not apply >>SH1<<... violet
Resolve all conflicts manually, mark them as resolved with
"git add/rm <conflicted_files>", then run "git rebase --continue".
You can instead skip this commit: run "git rebase --skip".
To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply >>SH1<<... violet

Ce que nous dit git ici:

  • il y a un conflit dans le fichier FILE_NAME,
  • 2 ajouts au même endroit (add/add)
  • Les commits problématiques SH1

Et qu’on a plusieurs options

  • On corrige le fichier FILE_NAME, on l’ajoute avec un git add et on demande au rebase de continuer avec un git rebase –continue
  • On zappe ce commit (ni vu ni connu) git rebase –skip
  • On panique et on annule tout git rebase –abort

Bob va prendre l’option 1, il sait ce qu’il a fait, il peut corriger le conflit.

NDLR; Notez que le conflit qui apparait serait apparu quoi qu’il arrive, c’est le fameux conflit qu’Alice a dû gérer dans notre situation de départ.

# Bob regarde quel fichier pose problème car il n'a pas lu le message
git status
# Bob voit que le problème est sur le fichier FILE_NAME
# Bob ouvre le fichier et corrige le conflit manuellement
# Bob va maintenant ajouter le fichier fraichement corrigé 
git add FILE_NAME
# Bob fait savoir a git que le conflit est résolut et que le rebase peut reprendre
git rebase --continue
# Bob push 
git push -f origin feat/violet
Après le rebase, (mais avant le push) Bob a corrigé les conflits dans sa branche locale.
Comme expliqué plus haut, une fois que Bob aura git push -f sa branche, le commit feature rouge original « disparaitra »

L’avantage ici:

  • On n’a pas de conflit au moment de la PR ! Donc Alice n’aura pas à résoudre les problèmes que Bob a causés
  • Mais surtout : on n’a pas besoin de faire un merge de develop dans notre feat/violet pour récupérer les modifications !
    (C’est tout l’avantage !!)

On passe donc de ça:

Beurk

A ça:

Propre

☄️ Un petit fix ?

Dans cette situation, Bob avait mergé « trop tôt » et créé un problème dans develop.

Déjà ça n’aurait pas dû arriver, on ne merge pas si ce n’est pas testé.

Maintenant, que celui ou celle à qui ça n’est jamais arrivé jette la première pierre à Bob.

Personne.

Donc comment on fait ?

DISCLAIMER : Ici on va être un peu dangereux, mais c’est aussi pour montrer qu’on peut faire tout et n’importe quoi et qu’il faut rester maitre de son dépôt.

Ce qu’on veut éviter c’est ça:

Remontons le fil.

Au moment où Alice alerte Bob, nous en sommes là:

Voici ce que Bob et Alice décident de faire

  1. Pour éviter que d’autres repartent sur une branche avec un bug, ils vont tout de suite remettre develop sur le commit bleu
    > Le commit orange sera donc perdu
  2. Bob va faire un fix depuis sa branche verte (ca lui prendra entre 1 et n essais, chaque essai aura son commit « toto », « test », « blabla », « fix try » etc, on fait tous le même).
  3. Bob va rebaser sa branche verte pour cacher ces commits que nous ne saurions voir.
  4. Bob va rouvrir une PR

Remettre develop au bon endroit

# Bob remet de suite develop à l'état du commit bleu
git push -f origin "sha1-commit-bleu":develop
# Bob récupère l'info sur son dépot local
git fetch

Faire les fix en local

Bob fait ses fix en local jusqu’à éliminer le problème, mais ne push pas (observez origin/feat/verte et feat/verte)

Une fois arrivé ici, le fix fonctionne. Bob va donc faire un rebase et merger tout cela:

Réécrire l’histoire

Depuis le début, on travaille sur 1 commit.
Lorsqu’on fait un git rebase -i, git affiche un « résumé » de ce qui va se passer dans l’éditeur selectionné (souvent vim ou nano), il faut alors « valider » cela pour continuer.

Dans les situations précédentes, on se contentait de sauvegarder et retour, ici cela va être un peu différent.

Quand Bob a fait son git rebase -i origin/develop, voila ce que git lui affiche:

pick 22d839f feature verte
pick 3f31c4b fix 1
pick 4f2a285 fix 2
pick 2b3055d fix 2 test

# Rebase 6d846a1..2b3055d onto 2b3055d (4 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup <commit> = like "squash", but discard this commit's log message
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
# .       create a merge commit using the original merge commit's
# .       message (or the oneline, if no original merge commit was
# .       specified). Use -c <commit> to reword the commit message.
#
# These lines can be re-ordered; they are executed from top to bottom.

Et c’est assez explicite, ce que nous voulons faire c’est que fix 1, fix 2 et fix 2 test n’apparaissent pas, et soit mergés dans vert !

Pour cela, on va modifier avant de sauvegarder en utilisant fixup

pick 22d839f feature verte
# On remplace le pick par f (pour fixup)
f 3f31c4b fix 1
# On remplace le pick par f (pour fixup)
f 4f2a285 fix 2
# On remplace le pick par f (pour fixup)
f 2b3055d fix 2 test

Bob enregistre ce fichier, le rebase se passe et créé un nouveau commit « vert » qui contient les 4 commits !!

Avant que Bob ne push sa nouvelle branche feat/verte, nous sommes donc dans cette situation

Le commit vert a un thème différent car il est différent.

En revanche, comme nous n’avons toujours pas push la branche feat/verte, le dépot origin a toujours l’ancienne référence.

git push -f origin feat/verte

Bob ouvre une PR, qu’Alice valide et nous avons donc ce résultat

On peut modifier un peu cette image pour al rendre plus propre.
En effet, les commits « vert » et merge sont « perdus » (ou disons qu’on n’a plus de pointeur pour y accéder).

On pourrait donc afficher:

Et tout est bien qui fini bien.

Attention cela dit:
Lorsque nous avons forcé la mise à jour de develop, c’était une opération dangereuse.
develop est une branche « partagée » et modifier son emplacement à la volée n’est pas une chose à prendre à la légère. Cela peut engendrer des soucis sur les dépôts des gens qui travaillent avec vous car leur référence est invalide !!
(C’est d’ailleurs pour cela que je n’ai jamais parlé de branche develop locale, on peut tout à fait s’en passer !!!)
Cet exemple est là pour montrer ce qu’il est possible de faire, mais il peut être très dangereux de modifier une branche « partagée » comme cela.
Dans un monde où on n’est pas certain de ce que l’on fait, il vaut mieux rouvrir une nouvelle branche et faire un fix. Tant pis pour le merge foireux, c’est toujours mieux que de perdre une après-midi à remettre les dépôts des autres à jour.


🧠 En conclusion

Pourquoi faire tout cela ?

Pour l’amour du code et d’un dépôt propre ? S’il n’y a que ça.

En fait, avoir un dépôt propre, ce n’est pas juste pour se la jouer Sheldon Cooper, ça a beaucoup d’avantages.

  • La lisibilité : en nommant correctement les commits de merge (ou de squash) vous savez entre 2 versions ce qui a été ajouté, retiré, fixé
  • Les revues de code : en corrigeant les conflits avant les MR/PR, vous épargnez à vos camarades de gérer vos problèmes
  • Les revues de code bis : en se rebasant sur la dernière version commune chaque fois, le code « commun » n’apparaîtra jamais dans les PR/MR, cela facilite la relecture.
  • L’identification de bug : entre 2 versions de la branche commune, il n’y a eu qu’une seule branche de mergée, avec une seule feature, donc par dichotomie on retrouve très rapidement où est le souci.
  • Et bien d’autres.

En revanche, il faut être attentif à ce que l’on fait.

  • Ne jamais rebaser une branche partagée. (Sinon préparez-vous à ramener les croissants)
  • Travailler sur SA branche et pas la branche des camarades.
  • Bien comprendre le principe de l’interactivité.

Et les GUI dans tout cela ?

Tout ce qui est expliqué ici est faisable dans les GUI, qui sont généralement très bien faits.
Mais juste comprendre sur quel bouton appuyer sans pour autant comprendre la mécanique derrière peut poser beaucoup de problèmes.
L’exemple le plus classique est celui du push refusé après rebase et d’un pull pour corriger le souci : c’est ce que le gui affichera « classiquement » et cela incite à l’erreur si on ne comprend pas pour quelles raisons cela arrive.

Au fait, vous avez remarqué que jamais Bob n’utilise de branche develop ou master en local?
Je pourrais vous dire qu’il n’y a aucun interêt a avoir une copie de ces branches sur son poste 🙂 Mais c’est un autre débat.


🔗 Liens utiles

Tout ça ne sort pas de ma tête, il existe un nombre de ressources intéressantes sur le sujet.
Voici quelques-unes qui m’ont bien aidé

https://nvie.com/posts/a-successful-git-branching-model/ (oui il est bien !)
https://www.youtube.com/watch?v=rt-9mPaYtKo (très intéressant)
https://www.atlassian.com/fr/git/tutorials/rewriting-history/git-rebase

Merci aussi à Jean-Baptiste pour sa relecture et ses conseils 🙂

Dernière modification: 18 mai 2020