Les conflits, étape par étape
- Leçon 10
- 40 min
- Module 4 : Résoudre et récupérer
Leçon 10 sur 15 · L'essentiel de Git et du développement en équipeLes conflits, étape par étape
1. Comprendre un dépôt
2. Travailler avec les branches et les dépôts distants
3. Collaborer par la revue de code
4. Résoudre et récupérer
5. Mises en production et correctifs urgents
Ce que vous saurez faire
Terminez une fusion quand vous et un collègue avez modifié la même ligne. Après cette leçon, vous pourrez lire les deux modifications et conserver l’intention de chaque personne. Vous pourrez tester le résultat et terminer la fusion, ou l’arrêter et recommencer.
Avant de commencerCe qu’il faut savoir et avoir sous la main
Ce que vous devez savoir
git pullrécupère les changements, puis fait une fusion. Avecpull.ff only, Git s’arrête quand les deux historiques sont différents. Vous l’avez appris dans Synchroniser de façon réfléchie : les deux personnes créent un commit en même temps.- Dans ce module, vous créez des commits (enregistrements de changements), fusionnez et annulez des commits sur
main. Ainsi, les commandes restent courtes. En équipe, vous faites chaque modification sur une branche et la fusionnez par une demande de tirage (pull request). C’est la démarche présentée dans Les étapes d’une demande de tirage.
Ce qu’il vous faut sur votre ordinateur
-
Les dépôts d’exercice dans
~/projects/nextia-learning-labs. Vous les avez clonés dans Les étapes d’une demande de tirage : préparer le laboratoire d’exercice. Si vous ne les avez pas, récupérez-les une fois :Fenêtre de terminal cd ~/projectsgit clone https://github.com/Nextia-Intelligence/nextia-learning-labs.git -
Préparez l’état de départ de ce module.
--resetsupprime l’ancien dossierc14-labet le recrée. Il ne change rien d’autre. Exécutez la même commande à tout moment pour recommencer ce module.Terminal cd ~/projectssh nextia-learning-labs/C14/setup.sh m04 --resetSortie Ready: /Users/amira/projects/c14-labticket-notes your clonesam-notes Sam's cloneteam-remote.git the shared remoteNext: cd c14-lab/ticket-notesTo start this scenario again: sh nextia-learning-labs/C14/setup.sh m04 --reset -
Entrez dans votre clone avec
cd c14-lab/ticket-notes.git statusafficheYour branch is ahead of 'origin/main' by 1 commit.(votre branche a un commit d’avance sur origin/main). -
Le script configure
pull.ff onlyetmerge.conflictStyle zdiff3dans les deux clones. Vos propres commits utilisent le nom défini dans Configurer Git : Étape 2 : indiquer votre identité à Git. -
Le script a créé ses commits avec des empreintes fixes, identiques à celles de cette leçon. Les commits que vous créez ont des empreintes différentes. Utilisez celles de votre propre sortie.
Quand Git ne peut pas fusionner seul
Section intitulée « Quand Git ne peut pas fusionner seul »Dans le module 2, Amira a fusionné le travail de Sam, et Git l’a fait seul. Git compare les deux versions ligne par ligne. Si chaque personne a modifié des lignes différentes, Git conserve les deux modifications.
Git utilise aussi une troisième version : la base, le dernier commit commun aux deux versions. Le module 3 l’appelait la base de fusion. La base montre ce que chaque personne a modifié. Si les deux personnes ont modifié la même ligne depuis la base, Git ne peut pas déterminer la bonne version. C’est un conflit. Git arrête la fusion, écrit les deux versions dans le fichier et attend votre décision.
Un conflit n’est pas une erreur, et rien n’est perdu. C’est une question à laquelle seule une personne peut répondre : que signifiait chaque modification, et que doit dire la ligne maintenant?
Dans une fusion, les deux versions portent des noms :
- Ours (la nôtre) est votre branche actuelle, celle vers laquelle pointe HEAD. Dans cette leçon, c’est la branche
maind’Amira. - Theirs (la leur) est le commit que vous intégrez par fusion. Dans cette leçon, c’est le commit de Sam provenant de
origin/main.
Afficher la base dans chaque conflit
Section intitulée « Afficher la base dans chaque conflit »Le script de préparation a configuré merge.conflictStyle zdiff3 dans les deux clones. Avec ce réglage, Git affiche aussi les lignes de base entre les deux versions. Vous pouvez alors voir ce que chaque personne a modifié, pas seulement le résultat. Activez ce réglage pour tous vos dépôts :
git config --global merge.conflictStyle zdiff3Exemple détaillé : deux modifications au billet 102
Section intitulée « Exemple détaillé : deux modifications au billet 102 »Le conflit
Section intitulée « Le conflit »Amira a ajouté une action au billet 102 : Sent a new reset link. (un nouveau lien de réinitialisation a été envoyé). En même temps, Sam a ajouté la cause du problème : The email was in the spam folder. (le courriel était dans le dossier des pourriels). Sam a poussé ses changements en premier. Amira essaie de pousser les siens :
git pushTo /Users/amira/projects/c14-lab/team-remote.git ! [rejected] main -> main (non-fast-forward)error: failed to push some refs to '/Users/amira/projects/c14-lab/team-remote.git'hint: Updates were rejected because the tip of your current branch is behindhint: its remote counterpart. If you want to integrate the remote changes,hint: use 'git pull' before pushing again.hint: See the 'Note about fast-forwards' in 'git push --help' for details.Elle récupère les changements. À cause de pull.ff only, Git les récupère seulement, puis s’arrête :
git pullFrom /Users/amira/projects/c14-lab/team-remote 05e00df..7e16da6 main -> origin/mainhint: Diverging branches can't be fast-forwarded, you need to either:...fatal: Not possible to fast-forward, aborting.Les historiques ont divergé. Elle décide de fusionner, comme dans le module 2 :
git pull --no-rebaseAuto-merging tickets.txtCONFLICT (content): Merge conflict in tickets.txtAutomatic merge failed; fix conflicts and then commit the result.La fusion a commencé, mais elle n’est pas terminée. Git n’a pas créé de commit de fusion. git status montre ce qui reste à régler :
git statusOn branch mainYour branch and 'origin/main' have diverged,and have 1 and 1 different commits each, respectively. (use "git pull" if you want to integrate the remote branch with yours)
You have unmerged paths. (fix conflicts and run "git commit") (use "git merge --abort" to abort the merge)
Unmerged paths: (use "git add <file>..." to mark resolution) both modified: tickets.txt
no changes added to commit (use "git add" and/or "git commit -a")both modified (modifié des deux côtés) signifie que les deux versions ont modifié tickets.txt au même endroit. Un chemin non fusionné est un fichier dont vous n’avez pas encore résolu le conflit. La sortie indique aussi les deux options : résoudre le conflit et créer un commit, ou abandonner la fusion.
Lire les marqueurs de conflit
Section intitulée « Lire les marqueurs de conflit »Amira ouvre tickets.txt dans son éditeur :
Ticket 101: printer offline. Restarted the spooler.<<<<<<< HEADTicket 102: password reset email not received. Sent a new reset link.||||||| 05e00dfTicket 102: password reset email not received.=======Ticket 102: password reset email not received. The email was in the spam folder.>>>>>>> 7e16da60a8af11e14488d6be51aeff28dadcfc1dTicket 103: shared drive is slow. Moved the user to the new server.Ticket 104: laptop will not charge. Replaced the power adapter.Git a écrit quatre lignes de marqueurs autour du conflit. Les lignes à l’extérieur des marqueurs ont fusionné sans problème.
<<<<<<< HEADcommence notre version : la version de la ligne d’Amira.||||||| 05e00dfcommence la base : la ligne dans05e00df, avant les deux modifications.=======commence leur version : la version de la ligne de Sam.>>>>>>> 7e16da6…termine le conflit. L’empreinte correspond au commit de Sam.
Comparez chaque version à la base. Amira a ajouté Sent a new reset link. Sam a ajouté The email was in the spam folder. Sans la base, il est plus difficile de voir que chaque personne a seulement ajouté du texte.
Comprendre l’intention de chaque personne
Section intitulée « Comprendre l’intention de chaque personne »Le texte d’une ligne montre ce qui a changé. Le message de commit explique pourquoi. git log --merge liste les commits de chaque côté qui ont modifié les fichiers en conflit :
git log --merge --oneline9e1b9df (HEAD -> main) Add the action for ticket 1027e16da6 (origin/main, origin/HEAD) Add the cause of ticket 102Pour voir la modification complète de Sam, elle utilise git show avec son empreinte :
git show 7e16da6commit 7e16da60a8af11e14488d6be51aeff28dadcfc1dAuthor: Sam Okafor <sam@example.com>Date: Tue Oct 6 09:10:00 2026 -0400
Add the cause of ticket 102
diff --git a/tickets.txt b/tickets.txtindex 76ca965..ae59119 100644--- a/tickets.txt+++ b/tickets.txt@@ -1,4 +1,4 @@ Ticket 101: printer offline. Restarted the spooler.Ticket 102: password reset email not received.Ticket 102: password reset email not received. The email was in the spam folder. Ticket 103: shared drive is slow. Moved the user to the new server. Ticket 104: laptop will not charge. Replaced the power adapter.Sam a noté la cause. Amira a noté l’action. Les deux faits sont vrais et utiles. La bonne ligne conserve donc les deux. Si elle ne comprend pas le sens d’une modification, elle demande à son auteur avant de décider.
Résoudre, tester et créer un commit
Section intitulée « Résoudre, tester et créer un commit »Pour résoudre un conflit, modifiez le fichier jusqu’à ce qu’il contienne le bon texte et aucun marqueur. Amira remplace les sept lignes de <<<<<<< à >>>>>>> par une seule ligne. La cause vient en premier, puis l’action :
Ticket 101: printer offline. Restarted the spooler.Ticket 102: password reset email not received. The email was in the spam folder. Sent a new reset link.Ticket 103: shared drive is slow. Moved the user to the new server.Ticket 104: laptop will not charge. Replaced the power adapter.Elle enregistre le fichier. Elle vérifie ensuite si elle a oublié des marqueurs. git diff --check signale les marqueurs de conflit restants. S’il n’en trouve aucun, il n’affiche rien :
git diff --checkEnsuite, elle exécute le test de l’équipe. check.sh est un petit script dans le dépôt. Il vérifie que chaque ligne de tickets.txt commence par Ticket <number>: (Billet suivi d’un numéro et d’un deux-points) :
sh check.shPASS: 4 ticket lines checkedUn fichier peut fusionner sans marqueurs et quand même être incorrect. Le test vous permet de le découvrir avant votre équipe.
Elle indique maintenant à Git que le conflit est résolu. git add marque le fichier comme résolu :
git add tickets.txtgit statusOn branch mainYour branch and 'origin/main' have diverged,and have 1 and 1 different commits each, respectively. (use "git pull" if you want to integrate the remote branch with yours)
All conflicts fixed but you are still merging. (use "git commit" to conclude merge)
Changes to be committed: modified: tickets.txtElle termine la fusion avec un commit. --no-edit conserve le message préparé par Git :
git commit --no-editgit log --oneline --graph -4[main 5c84cbf] Merge branch 'main' of /Users/amira/projects/c14-lab/team-remote* 5c84cbf (HEAD -> main) Merge branch 'main' of /Users/amira/projects/c14-lab/team-remote|\| * 7e16da6 (origin/main, origin/HEAD) Add the cause of ticket 102* | 9e1b9df Add the action for ticket 102|/* 05e00df Add ticket 104Le commit de fusion a deux parents : son commit et celui de Sam. Votre commit de fusion a une empreinte différente. Maintenant, main contient le travail de Sam. Elle peut donc pousser ses changements sans risque :
git pushTo /Users/amira/projects/c14-lab/team-remote.git 7e16da6..5c84cbf main -> mainArrêter une fusion et recommencer
Section intitulée « Arrêter une fusion et recommencer »Parfois, vous ne pouvez pas résoudre un conflit tout de suite. Vous devez peut-être consulter l’autre auteur, ou vous avez mal modifié le fichier. git merge --abort arrête la fusion. Il remet votre branche, la zone de préparation et les fichiers dans leur état d’avant la fusion.
Amira a essayé cette commande avant de résoudre le conflit. Elle l’a exécutée pendant que git status affichait encore You have unmerged paths (vous avez des chemins non fusionnés) :
git merge --abortgit statusgit log --oneline -1On branch mainYour branch and 'origin/main' have diverged,and have 1 and 1 different commits each, respectively. (use "git pull" if you want to integrate the remote branch with yours)
nothing to commit, working tree clean9e1b9df (HEAD -> main) Add the action for ticket 102main pointe de nouveau vers son propre commit, et le fichier ne contient aucun marqueur. Le commit de Sam reste dans origin/main, car la récupération n’est pas annulée. Quand elle est prête, elle exécute encore git pull --no-rebase, et le même conflit apparaît.
Exercice guidé : un conflit avec Sam
Section intitulée « Exercice guidé : un conflit avec Sam »D’abord, reproduisez l’exemple détaillé dans votre propre ticket-notes, de git push jusqu’au dernier git push. Ensuite, créez vous-même un deuxième conflit. Vous jouez Sam dans sam-notes et Amira dans ticket-notes, et vous modifiez tous les deux la ligne du billet 103.
-
Allez dans le clone de Sam et récupérez la fusion que vous avez poussée :
Fenêtre de terminal cd ~/projects/c14-lab/sam-notesgit pullLa sortie contient
Fast-forward(avance rapide). -
Dans votre éditeur, ouvrez
tickets.txtdanssam-notes. Remplacez la ligne du billet 103 par ce texte, puis enregistrez :Ticket 103: shared drive is slow. Moved the user to the new server. The user confirmed the fix. -
Créez un commit et poussez les changements en tant que Sam :
Fenêtre de terminal git commit -am "Close ticket 103"git push -
Allez dans votre clone. Remplacez la même ligne dans
ticket-notes/tickets.txtpar ce texte, puis enregistrez :Ticket 103: shared drive is slow. Moved the user to the new server. Ticket raised by Finance. -
Créez un commit, puis essayez de pousser les changements :
Fenêtre de terminal cd ~/projects/c14-lab/ticket-notesgit commit -am "Add who raised ticket 103"git pushLa commande affiche
! [rejected] main -> main (fetch first)(envoi rejeté : récupérez d’abord les changements). -
Fusionnez le travail de Sam :
Fenêtre de terminal git pull --no-rebaseLa sortie affiche
CONFLICT (content): Merge conflict in tickets.txt(conflit de contenu : conflit de fusion dans tickets.txt). -
Exécutez
git status.tickets.txtapparaît commeboth modified. -
Exécutez
git log --merge --oneline. La sortie affiche votre commit et celui de Sam,Close ticket 103(fermer le billet 103). -
Ouvrez
tickets.txt. Trouvez la ligne de base entre|||||||et=======. Comparez chaque version à cette ligne. -
Remplacez tout le bloc, de
<<<<<<<à>>>>>>>, par une ligne qui conserve les deux faits :Ticket 103: shared drive is slow. Moved the user to the new server. Ticket raised by Finance. The user confirmed the fix. -
Vérifiez et testez :
Fenêtre de terminal git diff --checksh check.shgit diff --checkn’affiche rien.check.shaffichePASS: 4 ticket lines checked(réussite : 4 lignes de billets vérifiées). -
Marquez le fichier comme résolu, terminez la fusion et poussez les changements :
Fenêtre de terminal git add tickets.txtgit commit --no-editgit push -
Exécutez
git log --oneline --graph -4. Le commit du haut est une fusion avec deux parents :Add who raised ticket 103(ajouter qui a ouvert le billet 103) etClose ticket 103.
À vous de jouer : quand un seul côté est correct
Section intitulée « À vous de jouer : quand un seul côté est correct »Un conflit ne nécessite pas toujours de garder les deux côtés. Créez ce conflit, puis décidez.
- Dans
sam-notes, exécutezgit pull. Remplacez la dernière ligne deREADME.mdparNotes about support tickets for the help desk. Use one line for each ticket.(Notes sur les billets de soutien du service d’assistance. Utilisez une ligne par billet.) Créez un commit avec le messageExplain the ticket line format in the README(Expliquer le format des lignes de billets dans le README), puis poussez. - Dans
ticket-notes, remplacez la même ligne parNotes about support tickets for the help desk. Write each ticket on one line.(Notes sur les billets de soutien du service d’assistance. Écrivez chaque billet sur une ligne.) Créez un commit avec le messageDescribe the ticket format(Décrire le format des billets). - Exécutez
git pull --no-rebase, puis résolvez le conflit dansREADME.md. Terminez la fusion et poussez.
Avant de modifier le fichier, répondez : que voulait chaque personne? Le résultat doit-il garder les deux côtés?
Afficher une réponse modèle
Voici à quoi ressemble le conflit. Vos deux empreintes sont différentes :
# Ticket notes
<<<<<<< HEADNotes about support tickets for the help desk. Write each ticket on one line.||||||| 928f2edNotes about support tickets for the help desk.=======Notes about support tickets for the help desk. Use one line for each ticket.>>>>>>> 555dcc3fcf504b021d15a76f90f351179bc04655git log --merge --oneline affiche les deux messages : Describe the ticket format et Explain the ticket line format in the README. Les deux personnes voulaient la même chose, mais l’ont exprimée avec des mots différents. Si vous gardez les deux côtés, le README répète la même règle. Gardez donc un seul côté. Ici, gardez la ligne de Sam, car sa version est déjà dans le dépôt distant :
# Ticket notes
Notes about support tickets for the help desk. Use one line for each ticket.Terminez ensuite comme avant :
git diff --checksh check.shgit add README.mdgit commit --no-editgit pushgit diff HEAD^1 HEAD montre comment la fusion a modifié votre côté : votre phrase a été remplacée par celle de Sam. Votre phrase reste dans votre commit Describe the ticket format. L’historique conserve donc les deux.
Erreur courante
Marqueurs de conflit dans un commit
Symptôme : après une fusion, sh check.sh échoue et affiche les lignes contenant des marqueurs :
FAIL: these lines in tickets.txt do not start with 'Ticket <number>: '2:<<<<<<< HEAD4:||||||| 05e00df6:=======8:>>>>>>> 7e16da60a8af11e14488d6be51aeff28dadcfc1dgit diff --check HEAD^ HEAD affiche tickets.txt:2: leftover conflict marker (marqueur de conflit restant), et la même chose pour les lignes 4, 6 et 8.
Cause : vous avez exécuté git add et git commit avant de supprimer les marqueurs. git add ne vérifie pas le contenu d’un fichier. Cette commande indique seulement à Git que vous avez terminé.
Solution : ne modifiez pas le commit de fusion. Corrigez le fichier dans un nouveau commit.
-
Ouvrez le fichier et modifiez le bloc pour qu’il contienne le bon texte, sans marqueurs.
-
Exécutez
git diff --checketsh check.sh. Le test doit afficherPASS(réussite). -
Créez un commit avec la correction :
Fenêtre de terminal git commit -am "Remove leftover conflict markers"Sortie [main 9a2eb8f] Remove leftover conflict markers1 file changed, 1 insertion(+), 7 deletions(-) -
Poussez. La prochaine fois, exécutez
git diff --checket le test avantgit add.
Erreur courante
Impossible de créer un commit, car certains fichiers ne sont pas fusionnés
Symptôme : vous avez modifié le fichier et supprimé les marqueurs. git commit --no-edit affiche :
error: Committing is not possible because you have unmerged files.hint: Fix them up in the work tree, and then use 'git add/rm <file>'hint: as appropriate to mark resolution and make a commit.fatal: Exiting because of an unresolved conflict.U tickets.txtCause : Git ne lit pas le fichier pour déterminer si vous avez terminé. Il attend git add. U signifie que le fichier n’est pas encore fusionné.
Solution : exécutez git add tickets.txt, puis de nouveau git commit --no-edit. git status affiche All conflicts fixed but you are still merging (Tous les conflits sont résolus, mais la fusion continue) quand le fichier est marqué comme résolu.
Vérifiez votre compréhension
Prédisez : le commit d'Amira modifie la ligne 2 de tickets.txt. Le commit de Sam ajoute une ligne à la fin du fichier. Est-ce que git pull --no-rebase s'arrête avec un conflit?
Afficher la réponse
Non. Les deux modifications sont à des endroits différents, et la ligne 2 n’est pas voisine de la dernière ligne. Git prend les deux modifications et crée le commit de fusion. Un conflit survient seulement si les deux côtés ont modifié les mêmes lignes, ou des lignes voisines, depuis la base. Malgré cela, exécutez le test après chaque fusion. Une fusion sans conflit peut quand même produire un résultat incorrect.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Vérifiez votre compréhension
Vérification pratique : après l'arrêt de git pull --no-rebase sur un conflit, listez les commandes qui terminent la fusion sans risque, dans l'ordre. Nommez ensuite la commande qui annule plutôt la fusion.
Afficher la réponse
git status, pour trouver les fichiers qui affichentboth modified(modifié des deux côtés).git log --merge --onelineetgit show <hash>, pour voir ce que chaque personne a modifié et pourquoi.- Modifiez chaque fichier, gardez le bon texte et supprimez tous les marqueurs.
git diff --check(n’affiche rien) et le test,sh check.sh(affichePASS).git add <file>pour chaque fichier résolu.git commit --no-edit, puisgit push.
git merge --abort annule la fusion et rétablit l’état d’avant son début.
Votre réponse contient-elle les points principaux de la nôtre ?
Connectez-vous et inscrivez-vous au cours pour enregistrer vos réponses. Chaque vérification compte pour le certificat.
Récapitulatif
- Un conflit survient quand les deux côtés ont modifié les mêmes lignes depuis la base. Git s’arrête et vous laisse décider.
- Dans une fusion, notre côté est votre branche actuelle (
HEAD), et leur côté est le commit que vous intégrez. Aveczdiff3, la base apparaît entre les deux. - Lisez les messages de commit avec
git log --mergeetgit showpour comprendre l’intention de chaque personne. Gardez ensuite les deux modifications, ou seulement celle qui est correcte. - Avant de créer un commit, exécutez
git diff --checket les tests. Ensuite,git addmarque le fichier comme résolu, etgit committermine la fusion. git merge --abortarrête une fusion et rétablit l’état d’avant son début.
Leçon suivante : Annuler en toute sécurité