<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Git on kenji.blog</title><link>http://kenji.blog/fr/categories/git/</link><description>Recent content in Git on kenji.blog</description><generator>Hugo -- gohugo.io</generator><language>fr</language><copyright>kenjinote</copyright><lastBuildDate>Sun, 13 Sep 2026 09:00:00 +0900</lastBuildDate><atom:link href="http://kenji.blog/fr/categories/git/index.xml" rel="self" type="application/rss+xml"/><item><title>【Commandes Git】La différence entre rebase et merge, et comment les utiliser correctement en pratique</title><link>http://kenji.blog/fr/p/git-rebase-vs-merge-practical-guide/</link><pubDate>Sun, 13 Sep 2026 09:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/git-rebase-vs-merge-practical-guide/</guid><description>&lt;img src="http://kenji.blog/p/git-rebase-vs-merge-practical-guide/img/eyecatch.jpg" alt="Featured image of post 【Commandes Git】La différence entre rebase et merge, et comment les utiliser correctement en pratique" />&lt;h1 id="1-introduction--pourquoi-le-choix-entre-merge-ou-rebase-est-il-un-débat-éternel-">1. Introduction : Pourquoi le choix entre &amp;ldquo;merge ou rebase&amp;rdquo; est-il un débat éternel ?
&lt;/h1>&lt;p>Git est un système de contrôle de version indispensable dans le développement logiciel moderne. Lorsque plusieurs développeurs modifient simultanément une base de code, le puissant modèle de branches de Git prend tout son sens. Cependant, dans le développement en équipe, le débat sur &amp;ldquo;s&amp;rsquo;il faut utiliser &lt;code>merge&lt;/code> ou &lt;code>rebase&lt;/code>&amp;rdquo; est un sujet qui tourmente constamment les développeurs, des débutants aux experts.&lt;/p>
&lt;p>Dans cet article, nous explorerons les différences de mécanisme entre &lt;code>git merge&lt;/code> et &lt;code>git rebase&lt;/code> en partant de la structure interne de Git, à savoir le graphe orienté acyclique (DAG) et les propriétés mathématiques des hachages de commit. Ensuite, nous expliquerons en profondeur comment les utiliser correctement en pratique, en nous appuyant sur des flux de travail (workflows) concrets. En allant au-delà d&amp;rsquo;une simple introduction aux commandes et en comprenant les calculs que Git effectue en arrière-plan, vous perdrez votre peur des conflits et serez en mesure de construire un historique propre et traçable.&lt;/p>
&lt;hr>
&lt;h1 id="2-structure-interne-de-git--hachages-de-commit-et-modèle-dobjets">2. Structure interne de Git : Hachages de commit et modèle d&amp;rsquo;objets
&lt;/h1>&lt;p>Pour comprendre comment Git intègre l&amp;rsquo;historique, il faut d&amp;rsquo;abord savoir comment Git stocke les données. Git ne sauvegarde pas simplement les différences (patchs) des modifications de fichiers, mais plutôt un instantané (snapshot) de l&amp;rsquo;ensemble du système de fichiers à un moment donné.&lt;/p>
&lt;h2 id="21-propriétés-cryptographiques-des-hachages-de-commit">2.1 Propriétés cryptographiques des hachages de commit
&lt;/h2>&lt;p>Chaque commit dans Git est identifié de manière unique par un nombre hexadécimal de 40 caractères calculé à partir de son contenu à l&amp;rsquo;aide de la fonction de hachage SHA-1 (Secure Hash Algorithm 1). L&amp;rsquo;objet commit est composé des éléments suivants :&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Pointeur vers l&amp;rsquo;objet Tree&lt;/strong> : Un instantané de la structure des répertoires et des fichiers (Blob) à ce moment-là.&lt;/li>
&lt;li>&lt;strong>Pointeurs vers les commits parents&lt;/strong> : Les valeurs de hachage d&amp;rsquo;un ou plusieurs commits parents (le premier commit n&amp;rsquo;a pas de parent, et un commit de fusion a deux parents ou plus).&lt;/li>
&lt;li>&lt;strong>Informations de l&amp;rsquo;auteur (Author)&lt;/strong> : La personne qui a écrit le code et la date/heure.&lt;/li>
&lt;li>&lt;strong>Informations du validateur (Committer)&lt;/strong> : La personne qui a créé/appliqué le commit et la date/heure.&lt;/li>
&lt;li>&lt;strong>Message de commit&lt;/strong> : Texte expliquant l&amp;rsquo;intention de la modification.&lt;/li>
&lt;/ol>
&lt;p>Exprimée mathématiquement, la valeur de hachage $H(C)$ pour l&amp;rsquo;objet commit $C$ est définie comme suit :&lt;/p>
$$
H(C) = \text{SHA-1}( \text{tree} \parallel \text{parent} \parallel \text{author} \parallel \text{committer} \parallel \text{message} )
$$&lt;p>Ici, $\parallel$ représente la concaténation des données. En raison des caractéristiques de la fonction de hachage, le simple fait de changer une lettre dans le message de commit, ou d&amp;rsquo;avoir un commit parent différent, générera une valeur de hachage complètement différente. En d&amp;rsquo;autres termes, &lt;strong>les commits sont immuables (Immutable)&lt;/strong>. Lorsque l&amp;rsquo;on dit que le &lt;code>rebase&lt;/code>, décrit plus loin, &amp;ldquo;réécrit l&amp;rsquo;historique&amp;rdquo;, c&amp;rsquo;est parce qu&amp;rsquo;il crée en fait de &amp;ldquo;nouveaux commits avec des contenus similaires mais des valeurs de hachage différentes&amp;rdquo;.&lt;/p>
&lt;p>La taille de l&amp;rsquo;espace de hachage est de $2^{160}$, et la probabilité $P$ qu&amp;rsquo;une collision (deux commits différents ayant la même valeur de hachage) se produise peut être approximée par la théorie du paradoxe des anniversaires (Birthday Paradox) comme suit ($n$ étant le nombre de commits) :&lt;/p>
$$
P(\text{collision}) \approx 1 - \exp\left(-\frac{n^2}{2 \times 2^{160}}\right)
$$&lt;p>Cette probabilité est extrêmement faible et, en pratique, il est presque impossible que les hachages de commit de Git entrent en collision.&lt;/p>
&lt;hr>
&lt;h1 id="3-théorie-des-graphes-et-dag--modèle-mathématique-de-lhistorique-git">3. Théorie des graphes et DAG : Modèle mathématique de l&amp;rsquo;historique Git
&lt;/h1>&lt;p>L&amp;rsquo;historique des commits de Git est modélisé comme un &amp;ldquo;graphe orienté acyclique&amp;rdquo; (Directed Acyclic Graph, DAG) en théorie des graphes.&lt;/p>
&lt;h2 id="31-quest-ce-quun-dag-graphe-orienté-acyclique-">3.1 Qu&amp;rsquo;est-ce qu&amp;rsquo;un DAG (graphe orienté acyclique) ?
&lt;/h2>&lt;p>Dans un graphe $G = (V, E)$, $V$ est l&amp;rsquo;ensemble des commits (sommets), et $E$ est l&amp;rsquo;ensemble des arêtes orientées montrant les relations parent-enfant entre les commits. Dans Git, la direction des arêtes va &amp;ldquo;du commit enfant vers le commit parent&amp;rdquo;. C&amp;rsquo;est parce le nouveau commit conserve un pointeur vers le commit passé.&lt;/p>
&lt;pre class="mermaid">
graph BT
A[&amp;#34;Commit A (Initial)&amp;#34;]
B[&amp;#34;Commit B&amp;#34;]
C[&amp;#34;Commit C (Principal)&amp;#34;]
D[&amp;#34;Commit D (Fonctionnalité)&amp;#34;]
E[&amp;#34;Commit E (Fusion)&amp;#34;]
B --&amp;gt; A
C --&amp;gt; B
D --&amp;gt; B
E --&amp;gt; C
E --&amp;gt; D
&lt;/pre>
&lt;p>La caractéristique principale d&amp;rsquo;un DAG est l&amp;rsquo;absence de cycles (boucles). Grâce à cela, les algorithmes qui remontent l&amp;rsquo;historique des commits ne tombent jamais dans une boucle infinie et peuvent atteindre la fin (le commit initial) à coup sûr.&lt;/p>
&lt;h2 id="32-tri-topologique-et-ordre-de-lhistorique">3.2 Tri topologique et ordre de l&amp;rsquo;historique
&lt;/h2>&lt;p>Lors de l&amp;rsquo;affichage de l&amp;rsquo;historique avec des commandes comme &lt;code>git log&lt;/code>, le DAG est ordonné sous forme de liste unidimensionnelle par un algorithme de tri topologique (Topological Sort). Pour toute arête orientée $u \to v$ ($u$ est l&amp;rsquo;enfant de $v$) dans le DAG, l&amp;rsquo;algorithme les réorganise de sorte que $u$ apparaisse avant $v$ dans la liste.&lt;/p>
&lt;hr>
&lt;h1 id="4-le-mécanisme-et-les-types-de-git-merge">4. Le mécanisme et les types de git merge
&lt;/h1>&lt;p>La commande la plus fondamentale pour intégrer les modifications d&amp;rsquo;une branche est &lt;code>git merge&lt;/code>. Cependant, en fonction de l&amp;rsquo;état actuel, Git choisit automatiquement une stratégie de fusion différente.&lt;/p>
&lt;h2 id="41-fusion-fast-forward---ff">4.1 Fusion Fast-Forward (&amp;ndash;ff)
&lt;/h2>&lt;p>Si la branche cible de l&amp;rsquo;intégration (ex. : &lt;code>main&lt;/code>) est un ancêtre direct de la branche source de l&amp;rsquo;intégration (ex. : &lt;code>feature&lt;/code>), Git effectue une fusion &amp;ldquo;Fast-Forward&amp;rdquo; (avance rapide). C&amp;rsquo;est une opération qui ne crée pas de nouveau commit, mais qui avance simplement le pointeur de la branche.&lt;/p>
&lt;pre class="mermaid">
gitGraph
commit id: &amp;#34;A&amp;#34;
commit id: &amp;#34;B&amp;#34;
branch feature
checkout feature
commit id: &amp;#34;C&amp;#34;
commit id: &amp;#34;D&amp;#34;
checkout main
merge feature
&lt;/pre>
&lt;p>La fusion Fast-Forward maintient l&amp;rsquo;historique en ligne droite, mais elle a l&amp;rsquo;inconvénient de perdre le contexte de &amp;ldquo;quels groupes de commits constituaient le développement d&amp;rsquo;une fonctionnalité (feature) spécifique&amp;rdquo;.&lt;/p>
&lt;h2 id="42-fusion-non-fast-forward---no-ff">4.2 Fusion Non-Fast-Forward (&amp;ndash;no-ff)
&lt;/h2>&lt;p>Si vous spécifiez explicitement &lt;code>git merge --no-ff&lt;/code>, Git créera toujours un nouveau &amp;ldquo;commit de fusion&amp;rdquo;, même dans une situation où le Fast-Forward est possible. Un commit de fusion est un commit spécial avec deux parents.&lt;/p>
&lt;pre class="mermaid">
gitGraph
commit id: &amp;#34;A&amp;#34;
commit id: &amp;#34;B&amp;#34;
branch feature
checkout feature
commit id: &amp;#34;C&amp;#34;
commit id: &amp;#34;D&amp;#34;
checkout main
commit id: &amp;#34;Travail Principal 1&amp;#34;
merge feature type: NORMAL
&lt;/pre>
&lt;p>L&amp;rsquo;avantage de cette méthode est que l&amp;rsquo;existence et l&amp;rsquo;histoire de la branche de fonctionnalité restent claires sur le DAG. Lorsqu&amp;rsquo;un problème survient, il est possible d&amp;rsquo;annuler (revert) en toute sécurité l&amp;rsquo;ensemble de la fonctionnalité en exécutant &lt;code>git revert -m 1 &amp;lt;hachage du commit de fusion&amp;gt;&lt;/code>.&lt;/p>
&lt;h2 id="43-algorithme-de-fusion-à-3-voies-3-way-merge">4.3 Algorithme de fusion à 3 voies (3-Way Merge)
&lt;/h2>&lt;p>Si la branche cible et la branche source ont chacune leurs propres commits, Git exécute une fusion à 3 voies. Git explore alors le DAG et trouve &amp;ldquo;l&amp;rsquo;ancêtre commun le plus proche&amp;rdquo; (Lowest Common Ancestor, LCA) des deux branches.&lt;/p>
&lt;p>La complexité algorithmique $T_{\text{LCA}}$ pour trouver le LCA peut être exécutée en temps linéaire par rapport au nombre de sommets $|V|$ et d&amp;rsquo;arêtes $|E|$ :&lt;/p>
$$
T_{\text{LCA}} = \mathcal{O}(|V| + |E|)
$$&lt;p>Git compare trois états : &amp;ldquo;l&amp;rsquo;état du LCA&amp;rdquo;, &amp;ldquo;l&amp;rsquo;état de la branche actuelle&amp;rdquo; et &amp;ldquo;l&amp;rsquo;état de l&amp;rsquo;autre branche&amp;rdquo;. S&amp;rsquo;il n&amp;rsquo;y a pas de conflit de modifications, il générera automatiquement un commit de fusion.&lt;/p>
&lt;hr>
&lt;h1 id="5-le-mécanisme-de-git-rebase-et-la-reconstruction-de-lhistorique">5. Le mécanisme de git rebase et la reconstruction de l&amp;rsquo;historique
&lt;/h1>&lt;p>Alors que &lt;code>git merge&lt;/code> &amp;ldquo;intègre&amp;rdquo; l&amp;rsquo;historique, &lt;code>git rebase&lt;/code> &amp;ldquo;reconstruit&amp;rdquo; (rattache) l&amp;rsquo;historique.&lt;/p>
&lt;h2 id="51-le-fonctionnement-interne-de-rebase">5.1 Le fonctionnement interne de Rebase
&lt;/h2>&lt;p>Lorsque vous rebasez la branche &lt;code>feature&lt;/code> sur la branche &lt;code>main&lt;/code> (&lt;code>git rebase main&lt;/code>), le fonctionnement interne est le suivant :&lt;/p>
&lt;ol>
&lt;li>Trouver l&amp;rsquo;ancêtre commun (LCA) entre la branche &lt;code>feature&lt;/code> et la branche &lt;code>main&lt;/code>.&lt;/li>
&lt;li>Sauvegarder dans une zone temporaire les différences des commits entre le LCA et l&amp;rsquo;extrémité de la branche &lt;code>feature&lt;/code>.&lt;/li>
&lt;li>Déplacer le pointeur de la branche &lt;code>feature&lt;/code> vers l&amp;rsquo;extrémité de la branche &lt;code>main&lt;/code>.&lt;/li>
&lt;li>Appliquer les différences sauvegardées une par une sur la nouvelle base (l&amp;rsquo;extrémité de &lt;code>main&lt;/code>) dans l&amp;rsquo;ordre (Cherry-Pick), créant ainsi de nouveaux commits.&lt;/li>
&lt;/ol>
&lt;pre class="mermaid">
graph TD
A[&amp;#34;Commit A&amp;#34;] --&amp;gt; B[&amp;#34;Commit B&amp;#34;]
B --&amp;gt; C[&amp;#34;Commit C (Principal)&amp;#34;]
B --&amp;gt; D[&amp;#34;Commit D (Ancienne Fonctionnalité)&amp;#34;]
D -.-&amp;gt; E[&amp;#34;Commit D&amp;#39; (Nouvelle Fonctionnalité)&amp;#34;]
C --&amp;gt; E
style D stroke-dasharray: 5 5, fill: #f9f9f9, color: #999
&lt;/pre>
&lt;p>Le point important ici est que le commit généré par le rebase $D'$ a &lt;strong>des commits parents différents du commit d&amp;rsquo;origine $D$, et aura donc une valeur de hachage complètement différente&lt;/strong> (voir la définition de la fonction de hachage $H(C)$ mentionnée précédemment).&lt;/p>
&lt;h2 id="52-rebase-interactif-interactive-rebase">5.2 Rebase interactif (Interactive Rebase)
&lt;/h2>&lt;p>L&amp;rsquo;utilisation de &lt;code>git rebase -i&lt;/code> (ou &lt;code>--interactive&lt;/code>) vous permet de manipuler l&amp;rsquo;historique des commits à votre guise. C&amp;rsquo;est l&amp;rsquo;outil ultime pour nettoyer l&amp;rsquo;historique local.&lt;/p>
&lt;ul>
&lt;li>&lt;code>pick&lt;/code> : Conserver le commit tel quel.&lt;/li>
&lt;li>&lt;code>reword&lt;/code> : Modifier uniquement le message du commit.&lt;/li>
&lt;li>&lt;code>edit&lt;/code> : Suspendre le processus pour modifier le contenu du commit.&lt;/li>
&lt;li>&lt;code>squash&lt;/code> : Fusionner ce commit avec le commit précédent et combiner leurs messages.&lt;/li>
&lt;li>&lt;code>fixup&lt;/code> : Semblable à &lt;code>squash&lt;/code>, mais ignore le message de ce commit.&lt;/li>
&lt;li>&lt;code>drop&lt;/code> : Supprimer complètement le commit.&lt;/li>
&lt;/ul>
&lt;p>D&amp;rsquo;un point de vue mathématique, si une branche contient $N$ commits, les variations (permutations) d&amp;rsquo;historique linéaire $P$ qui peuvent être générées en changeant l&amp;rsquo;ordre lors du rebase sont les suivantes :&lt;/p>
$$
P = N!
$$&lt;p>Git donne aux développeurs $N!$ degrés de liberté, ce qui leur permet de garder un historique logique et élégant.&lt;/p>
&lt;hr>
&lt;h1 id="6-la-règle-dor-du-rebase-the-golden-rule-of-rebase">6. La règle d&amp;rsquo;or du Rebase (The Golden Rule of Rebase)
&lt;/h1>&lt;p>Bien que &lt;code>rebase&lt;/code> soit très puissant, il existe une règle absolue.&lt;/p>
&lt;blockquote>
&lt;p>&lt;strong>&amp;ldquo;Ne jamais rebaser un historique public.&amp;rdquo;&lt;/strong>
&lt;em>(Never rebase public history)&lt;/em>&lt;/p>
&lt;/blockquote>
&lt;h2 id="61-pourquoi-ne-faut-il-pas-rebaser-un-historique-public-">6.1 Pourquoi ne faut-il pas rebaser un historique public ?
&lt;/h2>&lt;p>Git est distribué. Les commits que vous avez poussés sur &lt;code>origin/main&lt;/code> ont également été clonés (dupliqués) dans les dépôts locaux des autres développeurs. Si vous rebasez un commit déjà poussé pour réécrire l&amp;rsquo;historique, puis que vous forcez l&amp;rsquo;écrasement avec &lt;code>git push --force&lt;/code>, que se passera-t-il ?&lt;/p>
&lt;p>Le DAG local des autres développeurs et le DAG distant vont diverger fondamentalement. Lorsque les autres développeurs exécuteront &lt;code>git pull&lt;/code>, Git tentera de forcer la fusion de groupes de commits ayant des historiques différents, ce qui entraînera d&amp;rsquo;énormes conflits et des commits en double (des commits ayant le même contenu mais des hachages différents), plongeant le dépôt dans un état de panique.&lt;/p>
&lt;p>La règle d&amp;rsquo;or est de &lt;strong>&amp;ldquo;n&amp;rsquo;utiliser rebase que sur des branches locales qui n&amp;rsquo;ont pas encore été partagées avec d&amp;rsquo;autres&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;hr>
&lt;h1 id="7-résolution-des-conflits-et-git-rebase---continue">7. Résolution des conflits et git rebase &amp;ndash;continue
&lt;/h1>&lt;p>Si plusieurs personnes modifient la même partie d&amp;rsquo;un même fichier, un conflit se produit. Le processus de résolution des conflits est différent pour &lt;code>merge&lt;/code> et &lt;code>rebase&lt;/code>.&lt;/p>
&lt;h2 id="71-résolution-des-conflits-dans-merge">7.1 Résolution des conflits dans Merge
&lt;/h2>&lt;p>Avec &lt;code>git merge&lt;/code>, la résolution des conflits ne se produit &lt;strong>qu&amp;rsquo;une seule fois&lt;/strong>. Vous corrigez tous les conflits en une seule fois juste avant de créer le commit de fusion final.&lt;/p>
&lt;h2 id="72-résolution-des-conflits-dans-rebase">7.2 Résolution des conflits dans Rebase
&lt;/h2>&lt;p>Avec &lt;code>git rebase&lt;/code>, en raison de sa nature consistant à réappliquer les commits un par un, &lt;strong>un conflit peut survenir pour chaque commit&lt;/strong>.&lt;/p>
&lt;p>Si un conflit survient pendant le rebase, Git interrompt le processus. Le flux de résolution est le suivant :&lt;/p>
&lt;ol>
&lt;li>Ouvrez un éditeur de texte ou un IDE (comme VS Code) et corrigez manuellement les marqueurs de conflit (&lt;code>&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/code>, &lt;code>======&lt;/code>, &lt;code>&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/code>).&lt;/li>
&lt;li>Ajoutez les fichiers corrigés à l&amp;rsquo;index :
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git add &amp;lt;fichiers_modifiés&amp;gt;
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>Sans créer de commit, reprenez le processus de rebase :
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git rebase --continue
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>Si vous souhaitez annuler le rebase lui-même et revenir à l&amp;rsquo;état d&amp;rsquo;origine, exécutez la commande suivante :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git rebase --abort
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>(&lt;em>Si la résolution d&amp;rsquo;un conflit n&amp;rsquo;est pas nécessaire et que vous souhaitez sauter ce commit, utilisez &lt;code>git rebase --skip&lt;/code>.&lt;/em>)&lt;/p>
&lt;hr>
&lt;h1 id="8-utilisation-correcte-en-pratique-pratiques-de-workflow">8. Utilisation correcte en pratique (Pratiques de Workflow)
&lt;/h1>&lt;p>Alors, comment devez-vous utiliser &lt;code>merge&lt;/code> et &lt;code>rebase&lt;/code> dans des environnements de développement réels ? Voici l&amp;rsquo;approche la plus standard et la plus sûre.&lt;/p>
&lt;h2 id="81-scénario-1-nettoyer-lhistorique-de-travail-local-utilisation-de-rebase">8.1 [Scénario 1] Nettoyer l&amp;rsquo;historique de travail local (Utilisation de Rebase)
&lt;/h2>&lt;p>Supposons que vous développiez sur une branche de fonctionnalité et que de nombreux petits commits (comme des &amp;ldquo;corrections de fautes de frappe&amp;rdquo; ou &amp;ldquo;sauvegardes temporaires&amp;rdquo;) se soient accumulés. Avant de créer une Pull Request (PR), utilisez le rebase interactif pour les organiser en unités significatives.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Exécuté sur la branche feature&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase -i HEAD~5
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># (L&amp;#39;éditeur s&amp;#39;ouvre, et vous pouvez utiliser squash et fixup pour nettoyer l&amp;#39;historique)&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Cela crée un historique de commits clair, rendant vos intentions facilement compréhensibles pour le réviseur.&lt;/p>
&lt;h2 id="82-scénario-2-suivre-les-dernières-modifications-de-la-branche-main-utilisation-de-rebase">8.2 [Scénario 2] Suivre les dernières modifications de la branche main (Utilisation de Rebase)
&lt;/h2>&lt;p>Si le développement prend du temps et que les modifications des autres sont continuellement fusionnées dans la branche &lt;code>main&lt;/code>, votre branche &lt;code>feature&lt;/code> deviendra obsolète. Dans ce cas, suivez le rythme en rebasant votre branche &lt;code>feature&lt;/code> sur la dernière version de &lt;code>main&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Récupérer les dernières informations de main&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git fetch origin
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Rattacher la branche feature au sommet de la dernière version de main&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git rebase origin/main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Cela maintient un historique en ligne droite et permet d&amp;rsquo;éviter les conflits lors de la fusion ultérieure. Cela empêche également la création de commits de fusion inutiles (&amp;ldquo;Merge branch &amp;lsquo;main&amp;rsquo; into feature&amp;rdquo;).&lt;/p>
&lt;h2 id="83-scénario-3-intégration-de-fonctionnalités-terminées-utilisation-de-merge">8.3 [Scénario 3] Intégration de fonctionnalités terminées (Utilisation de Merge)
&lt;/h2>&lt;p>Une fois le développement sur la branche &lt;code>feature&lt;/code> terminé, il est temps de l&amp;rsquo;intégrer dans la branche &lt;code>main&lt;/code>. Ici, utilisez &lt;strong>&lt;code>git merge --no-ff&lt;/code>&lt;/strong> (c&amp;rsquo;est la même chose que de choisir &amp;ldquo;Create a merge commit&amp;rdquo; dans une Pull Request sur GitHub).&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">git checkout main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git merge --no-ff feature -m &lt;span class="s2">&amp;#34;Merge feature: Implémentation de la fonction de connexion utilisateur&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">git push origin main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Cela laisse un point nodal historique (un commit de fusion) sur le DAG de la branche &lt;code>main&lt;/code>, indiquant qu&amp;rsquo;&amp;ldquo;une fonctionnalité a été fusionnée ici&amp;rdquo;. Lorsque vous regardez l&amp;rsquo;historique plus tard, il est plus facile de suivre le code par fonctionnalité.&lt;/p>
&lt;hr>
&lt;h1 id="9-conclusion-résumé">9. Conclusion (Résumé)
&lt;/h1>&lt;p>Lors de l&amp;rsquo;utilisation de Git, les approches extrêmes telles que &amp;ldquo;tout résoudre avec Merge&amp;rdquo; ou &amp;ldquo;tout garder en ligne droite avec Rebase&amp;rdquo; ont chacune leurs avantages et leurs inconvénients.&lt;/p>
&lt;p>La meilleure pratique en milieu professionnel est une approche hybride : &lt;strong>&amp;ldquo;utiliser rebase pour nettoyer élégamment l&amp;rsquo;historique privé local, et utiliser merge &amp;ndash;no-ff pour conserver le contexte dans l&amp;rsquo;historique public d&amp;rsquo;intégration&amp;rdquo;&lt;/strong>.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Local (espace de travail personnel)&lt;/strong> : Utilisez &lt;code>rebase&lt;/code> pour éliminer les commits inutiles et maintenir un historique linéaire en suivant les dernières modifications de la branche principale.&lt;/li>
&lt;li>&lt;strong>Global (espace de travail partagé)&lt;/strong> : Utilisez &lt;code>merge --no-ff&lt;/code> pour enregistrer l&amp;rsquo;existence de la branche de fonctionnalité sous forme de commit de fusion dans le DAG, facilitant ainsi les reverts et le suivi.&lt;/li>
&lt;/ul>
&lt;p>En comprenant le contexte mathématique et architectural tel que la structure du DAG et le fonctionnement de la fonction de hachage, les commandes Git passent de la simple mémorisation à la &amp;ldquo;conception intentionnelle d&amp;rsquo;un historique&amp;rdquo;. En respectant la règle d&amp;rsquo;or du rebase, choisissez les commandes optimales pour chaque situation et construisez un historique de commits propre, facile à lire et à maintenir pour toute l&amp;rsquo;équipe.&lt;/p></description></item><item><title>Erreurs courantes des débutants sur Git et commandes de résolution (résolution de conflits, etc.)</title><link>http://kenji.blog/fr/p/git-beginners-mistakes-and-solutions/</link><pubDate>Sat, 12 Sep 2026 17:00:00 +0900</pubDate><guid>http://kenji.blog/fr/p/git-beginners-mistakes-and-solutions/</guid><description>&lt;img src="http://kenji.blog/p/git-beginners-mistakes-and-solutions/img/eyecatch.jpg" alt="Featured image of post Erreurs courantes des débutants sur Git et commandes de résolution (résolution de conflits, etc.)" />&lt;h1 id="erreurs-courantes-des-débutants-sur-git-et-commandes-de-résolution-résolution-de-conflits-etc">Erreurs courantes des débutants sur Git et commandes de résolution (résolution de conflits, etc.)
&lt;/h1>&lt;h2 id="1-introduction--pourquoi-fait-on-des-erreurs-sur-git-">1. Introduction : Pourquoi fait-on des erreurs sur Git ?
&lt;/h2>&lt;p>Dans le développement logiciel, Git est devenu aussi indispensable que l&amp;rsquo;air ou l&amp;rsquo;eau. Cependant, pour de nombreux débutants (et parfois même pour les experts), Git peut sembler être une &amp;ldquo;boîte noire magique et effrayante&amp;rdquo;. Des commits qui disparaissent, des modifications massives poussées sur la mauvaise branche, des messages d&amp;rsquo;erreur de conflit inédits remplissant l&amp;rsquo;écran&amp;hellip; Lorsqu&amp;rsquo;on tombe dans ces &amp;ldquo;pièges de Git&amp;rdquo;, la progression du travail s&amp;rsquo;arrête complètement, et dans le pire des cas, on est envahi par la peur de détruire le code source.&lt;/p>
&lt;p>Pourquoi Git est-il si difficile et si propice aux erreurs ? La raison principale est que &amp;ldquo;les utilisateurs mémorisent et utilisent des commandes superficielles sans comprendre ce qui se passe à l&amp;rsquo;intérieur de Git&amp;rdquo;. Bien que Git soit basé sur la conception robuste d&amp;rsquo;un système de contrôle de version décentralisé (DVCS), son interface (CLI) n&amp;rsquo;est pas toujours intuitive.&lt;/p>
&lt;p>Dans cet article, nous classerons en de nombreux cas les &amp;ldquo;gaffes (erreurs courantes)&amp;rdquo; que les débutants sur Git rencontrent fréquemment sur le terrain, et nous présenterons les commandes spécifiques pour les résoudre. Cependant, il ne s&amp;rsquo;agira pas d&amp;rsquo;une simple liste de commandes (antisèche). Nous explorerons en profondeur, sur plus de 10 000 caractères, &amp;ldquo;pourquoi cette erreur se produit&amp;rdquo; et &amp;ldquo;comment les données se déplacent à l&amp;rsquo;intérieur de Git lors de l&amp;rsquo;exécution de cette commande&amp;rdquo;, en utilisant la structure du répertoire &lt;code>.git&lt;/code>, le contexte mathématique de l&amp;rsquo;algorithme Diff en arrière-plan, et des diagrammes Mermaid.&lt;/p>
&lt;p>À la fin de cet article, vous devriez être libéré de la peur de Git et convaincu que &amp;ldquo;Git est le partenaire le plus fiable&amp;rdquo;. Plongeons maintenant dans le monde profond de Git.&lt;/p>
&lt;hr>
&lt;h2 id="2-les-abysses-de-git--comprendre-la-structure-interne-du-répertoire-git">2. Les abysses de Git : Comprendre la structure interne du répertoire &lt;code>.git&lt;/code>
&lt;/h2>&lt;p>La première étape pour faciliter le dépannage est de savoir comment Git stocke les données. Le dossier caché &lt;code>.git&lt;/code> situé à la racine de votre projet est le cœur de Git. Git ne gère pas les données comme un simple système enregistrant séquentiellement les différences de fichiers (patchs), mais comme un &lt;strong>flux d&amp;rsquo;instantanés (snapshots)&lt;/strong>.&lt;/p>
&lt;h3 id="21-modèle-dobjet--blob-tree-commit">2.1 Modèle d&amp;rsquo;objet : Blob, Tree, Commit
&lt;/h3>&lt;p>Git utilise principalement trois objets pour représenter l&amp;rsquo;état du dépôt. Ces objets sont stockés dans &lt;code>.git/objects&lt;/code>.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Blob (Binary Large Object)&lt;/strong>
C&amp;rsquo;est l&amp;rsquo;objet qui stocke le contenu du fichier lui-même. Les noms de fichiers et les informations d&amp;rsquo;autorisation n&amp;rsquo;y sont pas inclus. Il s&amp;rsquo;agit d&amp;rsquo;une pure séquence d&amp;rsquo;octets compressée avec zlib et identifiée par une valeur de hachage SHA-1 (40 caractères hexadécimaux).&lt;/li>
&lt;li>&lt;strong>Tree&lt;/strong>
C&amp;rsquo;est l&amp;rsquo;objet qui représente la structure du répertoire. Un objet Tree contient des pointeurs (valeurs de hachage SHA-1) vers d&amp;rsquo;autres objets Tree (sous-répertoires) ou objets Blob (fichiers), ainsi que leurs noms de fichiers et autorisations d&amp;rsquo;accès. Il joue un rôle similaire à un répertoire UNIX.&lt;/li>
&lt;li>&lt;strong>Commit&lt;/strong>
Il contient un pointeur vers l&amp;rsquo;objet Tree de niveau supérieur de l&amp;rsquo;ensemble du dépôt à un moment donné, des métadonnées (auteur, date du commit, message de commit) et un pointeur vers le commit précédent (commit parent).&lt;/li>
&lt;/ol>
&lt;pre class="mermaid">
graph TD
Commit1[&amp;#34;Commit (Hash: 9f8a)&amp;#34;] --&amp;gt; Tree1[&amp;#34;Tree (Hash: 4b82)&amp;#34;]
Tree1 --&amp;gt; Blob1[&amp;#34;Blob (Hash: 8d7e) : index.js&amp;#34;]
Tree1 --&amp;gt; Tree2[&amp;#34;Tree (Hash: 3a2c) : src/&amp;#34;]
Tree2 --&amp;gt; Blob2[&amp;#34;Blob (Hash: 5f1b) : app.js&amp;#34;]
&lt;/pre>
&lt;h3 id="22-la-véritable-nature-de-head-et-des-références-refs">2.2 La véritable nature de HEAD et des références (Refs)
&lt;/h3>&lt;p>En travaillant avec Git, on voit souvent le mot &lt;code>HEAD&lt;/code>. Il s&amp;rsquo;agit d&amp;rsquo;une &lt;strong>référence symbolique (Symbolic Reference)&lt;/strong> qui pointe vers la branche (ou le commit) actuellement extraite.
Si vous ouvrez le fichier &lt;code>.git/HEAD&lt;/code> avec un éditeur de texte, vous verrez la chaîne suivante :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">ref: refs/heads/main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Cela signifie que &amp;ldquo;l&amp;rsquo;état actuel se trouve à la pointe de la branche &lt;code>main&lt;/code>&amp;rdquo;. Et si vous ouvrez &lt;code>.git/refs/heads/main&lt;/code>, vous y trouverez un hachage SHA-1 de 40 caractères, qui pointe vers le dernier objet Commit.
Une branche Git n&amp;rsquo;est rien d&amp;rsquo;autre qu&amp;rsquo;un pointeur léger (un fichier) qui pointe vers un commit spécifique. Le simple fait de savoir cela dissipe la peur que &amp;ldquo;supprimer une branche supprimera tous les fichiers&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="3-git-décrypté-par-les-mathématiques--algorithme-diff-et-fonctions-de-hachage">3. Git décrypté par les mathématiques : Algorithme Diff et fonctions de hachage
&lt;/h2>&lt;p>Lorsque Git détecte des conflits ou affiche des différences de fichiers, un algorithme avancé fonctionne en arrière-plan.&lt;/p>
&lt;h3 id="31-algorithme-diff-de-myers">3.1 Algorithme Diff de Myers
&lt;/h3>&lt;p>L&amp;rsquo;algorithme de détection de différences par défaut de Git est celui inventé par Eugene W. Myers. Étant donné deux fichiers texte $A$ et $B$, le problème de trouver la &amp;ldquo;séquence minimale d&amp;rsquo;édition (insertions et suppressions)&amp;rdquo; pour convertir $A$ en $B$ peut être modélisé comme un problème de plus court chemin dans la théorie des graphes.&lt;/p>
&lt;p>Soient $N$ et $M$ les longueurs des chaînes, et $V = N + M$ le total. L&amp;rsquo;algorithme de Myers recherche la distance d&amp;rsquo;édition (Edit Distance) $D$. La complexité temporelle de cet algorithme est exprimée par l&amp;rsquo;équation suivante :&lt;/p>
$$ \mathcal{O}(V \cdot D) $$&lt;p>Ici, si la différence entre les fichiers est petite (c&amp;rsquo;est-à-dire que $D$ est petit), l&amp;rsquo;algorithme fonctionne très rapidement en $\mathcal{O}(V)$. Cependant, si les fichiers est complètement différents, $D \approx V$, et la complexité temporelle dans le pire des cas est de $\mathcal{O}(V^2)$.&lt;/p>
&lt;h3 id="32-patience-diff-et-histogram-diff">3.2 Patience Diff et Histogram Diff
&lt;/h3>&lt;p>L&amp;rsquo;algorithme de Myers est excellent, mais il peut générer des différences qui ne sont pas intuitives (dénuées de sens) pour les humains, par exemple lors d&amp;rsquo;un grand changement dans l&amp;rsquo;ordre des fonctions ou des classes. Pour résoudre ce problème, Git implémente &lt;code>Patience Diff&lt;/code> et &lt;code>Histogram Diff&lt;/code>.&lt;/p>
&lt;p>Patience Diff se concentre sur &amp;ldquo;les lignes uniques qui n&amp;rsquo;apparaissent qu&amp;rsquo;une seule fois dans les deux fichiers&amp;rdquo; et trouve leur plus longue sous-séquence commune (Longest Common Subsequence : LCS). Si le nombre d&amp;rsquo;éléments uniques est $U$, le calcul de la LCS peut être résolu avec la complexité suivante :&lt;/p>
$$ \mathcal{O}(U \log U) $$&lt;p>Lorsque vous trouvez qu&amp;rsquo;il est difficile de résoudre un conflit, une solution consiste à utiliser &lt;code>git diff --histogram&lt;/code> ou à spécifier cet algorithme dans la stratégie de fusion (&lt;code>git merge -s recursive -X histogram&lt;/code>).&lt;/p>
&lt;h3 id="33-sha-1-et-probabilité-de-collision">3.3 SHA-1 et probabilité de collision
&lt;/h3>&lt;p>Git gère tous les objets avec des valeurs de hachage SHA-1. La taille de l&amp;rsquo;espace de hachage est de $2^{160}$. En approximant la probabilité d&amp;rsquo;une collision de hachage (le fait que différents contenus aient la même valeur de hachage) à l&amp;rsquo;aide du paradoxe des anniversaires (Birthday Paradox), le nombre d&amp;rsquo;objets $k$ requis pour que la probabilité de collision $p$ atteigne 50 % est le suivant :&lt;/p>
$$ k \approx \sqrt{2 \ln(2)} \cdot 2^{80} \approx 1.2 \times 2^{80} $$&lt;p>Il s&amp;rsquo;agit d&amp;rsquo;un nombre astronomique, et la probabilité qu&amp;rsquo;une collision involontaire se produise dans le développement logiciel normal est pratiquement nulle. Par conséquent, Git fonctionne en faisant confiance à la valeur de hachage comme un &amp;ldquo;ID unique absolu&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="4-étude-de-cas-1--jai-commité-sur-la-mauvaise-branche-">4. Étude de cas 1 : J&amp;rsquo;ai commité sur la mauvaise branche !
&lt;/h2>&lt;p>&lt;strong>【Situation】&lt;/strong>
Sans me rendre compte que je travaillais sur la branche &lt;code>main&lt;/code>, j&amp;rsquo;ai écrit beaucoup de code pour une nouvelle fonctionnalité et, pire encore, j&amp;rsquo;ai même fait un &lt;code>git commit&lt;/code>. J&amp;rsquo;étais censé créer une branche &lt;code>feature/login&lt;/code> et y travailler !&lt;/p>
&lt;h3 id="solution--git-reset-et-création-de-branche">Solution : &lt;code>git reset&lt;/code> et création de branche
&lt;/h3>&lt;p>Dans Git, les commits sont des objets indépendants et les branches ne sont que des pointeurs. Par conséquent, cela peut être résolu instantanément par l&amp;rsquo;opération : &amp;ldquo;créer une nouvelle branche, puis reculer le pointeur de la branche actuelle&amp;rdquo;.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;span class="lnt">8
&lt;/span>&lt;span class="lnt">9
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Créer une nouvelle branche pointant vers le commit actuel (le commit fait par erreur)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git branch feature/login
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Reculer le pointeur de la branche main au commit précédent (HEAD~1)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># L&amp;#39;utilisation de --keep permet de réinitialiser en toute sécurité tout en conservant les modifications non commitées dans le répertoire de travail.&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git reset --keep HEAD~1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Basculer sur la bonne branche&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git checkout feature/login
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h3 id="explication-illustrée--que-sest-il-passé-en-interne-">Explication illustrée : Que s&amp;rsquo;est-il passé en interne ?
&lt;/h3>&lt;p>Visualisons le mouvement du pointeur de branche à ce moment-là à l&amp;rsquo;aide de &lt;code>gitGraph&lt;/code> de Mermaid.&lt;/p>
&lt;pre class="mermaid">
gitGraph
commit id: &amp;#34;Commit initial&amp;#34;
commit id: &amp;#34;Correction de bug&amp;#34;
commit id: &amp;#34;Commit erroné&amp;#34; type: HIGHLIGHT
branch feature/login
checkout feature/login
checkout main
&lt;/pre>
&lt;p>Au début, &lt;code>main&lt;/code> et &lt;code>HEAD&lt;/code> pointaient vers &amp;ldquo;Commit erroné&amp;rdquo;, mais &lt;code>git branch feature/login&lt;/code> y crée un nouveau pointeur. Ensuite, avec &lt;code>git reset&lt;/code>, seul le pointeur &lt;code>main&lt;/code> revient à la position de &amp;ldquo;Correction de bug&amp;rdquo;. Aucun objet n&amp;rsquo;est supprimé.&lt;/p>
&lt;hr>
&lt;h2 id="5-étude-de-cas-2--je-veux-annuler-un-commit-déjà-poussé-">5. Étude de cas 2 : Je veux annuler un commit déjà poussé !
&lt;/h2>&lt;p>&lt;strong>【Situation】&lt;/strong>
Tard dans la nuit, j&amp;rsquo;ai commité du code plein de bugs et je l&amp;rsquo;ai rendu public sur le dépôt distant avec &lt;code>git push origin main&lt;/code>. Je réalise qu&amp;rsquo;il y a un bug majeur et je pâlis.&lt;/p>
&lt;h3 id="solution-1--annuler-lhistoire-avec-git-revert-recommandé--sûr">Solution 1 : Annuler l&amp;rsquo;histoire avec &lt;code>git revert&lt;/code> (Recommandé / Sûr)
&lt;/h3>&lt;p>Dans le développement en équipe, il est strictement interdit d&amp;rsquo;altérer l&amp;rsquo;historique des commits déjà poussés en utilisant &lt;code>git reset&lt;/code> ou similaire. Cela briserait la cohérence avec les dépôts locaux des autres développeurs. La bonne approche est de &lt;strong>&amp;ldquo;créer un nouveau commit inverse qui annule complètement les modifications du commit erroné&amp;rdquo;&lt;/strong>. C&amp;rsquo;est ce que fait &lt;code>git revert&lt;/code>.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Créer un commit qui annule le dernier commit&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git revert HEAD
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">[&lt;/span>main 7f3a8b2&lt;span class="o">]&lt;/span> Revert &lt;span class="s2">&amp;#34;Message du commit erroné&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="m">1&lt;/span> file changed, &lt;span class="m">1&lt;/span> insertion&lt;span class="o">(&lt;/span>+&lt;span class="o">)&lt;/span>, &lt;span class="m">10&lt;/span> deletions&lt;span class="o">(&lt;/span>-&lt;span class="o">)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Pousser vers le dépôt distant&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git push origin main
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;pre class="mermaid">
gitGraph
commit id: &amp;#34;Commit A&amp;#34;
commit id: &amp;#34;Commit B (Erreur)&amp;#34;
commit id: &amp;#34;Revert Commit B&amp;#34; type: REVERSE
&lt;/pre>
&lt;p>L&amp;rsquo;histoire continue d&amp;rsquo;avancer, seul l&amp;rsquo;état du code revient à la normale.&lt;/p>
&lt;h3 id="solution-2--altérer-lhistoire-avec-git-push---force-with-lease">Solution 2 : Altérer l&amp;rsquo;histoire avec &lt;code>git push --force-with-lease&lt;/code>
&lt;/h3>&lt;p>Si vous venez de pousser sur une branche que vous êtes le seul à utiliser, altérer l&amp;rsquo;historique peut être acceptable.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;span class="lnt">6
&lt;/span>&lt;span class="lnt">7
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Réinitialiser le commit localement et corriger&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git reset --hard HEAD~1
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git add .
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git commit -m &lt;span class="s2">&amp;#34;Correct implementation&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Écraser de force l&amp;#39;historique distant&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git push origin feature/login --force-with-lease
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>&lt;code>--force-with-lease&lt;/code> est un push forcé sécurisé pour éviter d&amp;rsquo;écraser accidentellement le travail de quelqu&amp;rsquo;un d&amp;rsquo;autre.&lt;/p>
&lt;hr>
&lt;h2 id="6-étude-de-cas-3--je-veux-changer-de-branche-en-plein-travail-la-magie-de-stash">6. Étude de cas 3 : Je veux changer de branche en plein travail (La magie de Stash)
&lt;/h2>&lt;p>&lt;strong>【Situation】&lt;/strong>
Je suis en train d&amp;rsquo;implémenter une nouvelle fonctionnalité sur la branche &lt;code>feature/A&lt;/code>, le code source est dans un état intermédiaire qui ne compile même pas encore. Soudain, mon patron me dit : &amp;ldquo;Il y a un bug urgent en production sur la branche &lt;code>main&lt;/code>, corrige-le tout de suite !&amp;rdquo;&lt;/p>
&lt;h3 id="solution--mettre-de-côté-avec-git-stash">Solution : Mettre de côté avec &lt;code>git stash&lt;/code>
&lt;/h3>&lt;p>&lt;code>git stash&lt;/code> est une commande qui met de côté les modifications non commitées dans une zone temporaire.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 1. Mettre de côté les modifications en cours&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git stash push -m &lt;span class="s2">&amp;#34;WIP: feature A partially implemented&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 2. Possibilité de basculer sur la branche main&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git checkout main
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># ... (travail de correction de bug urgent, commit et push) ...&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 3. Retourner à la branche d&amp;#39;origine une fois le travail terminé&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git checkout feature/A
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># 4. Restaurer les modifications mises de côté&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git stash pop
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Lors de l&amp;rsquo;exécution de &lt;code>git stash&lt;/code>, Git crée en interne deux objets commit spéciaux et les stocke dans une référence appelée &lt;code>refs/stash&lt;/code>. En d&amp;rsquo;autres termes, un Stash est finalement un &amp;ldquo;commit temporaire sans nom&amp;rdquo;.&lt;/p>
&lt;hr>
&lt;h2 id="7-étude-de-cas-4--létat-terrifiant-detached-head">7. Étude de cas 4 : L&amp;rsquo;état terrifiant &amp;ldquo;Detached HEAD&amp;rdquo;
&lt;/h2>&lt;p>&lt;strong>【Situation】&lt;/strong>
Je voulais vérifier le code à un moment précis dans le passé et j&amp;rsquo;ai exécuté &lt;code>git checkout 9f8a7b6&lt;/code>. Le message &lt;code>You are in 'detached HEAD' state.&lt;/code> s&amp;rsquo;est affiché. J&amp;rsquo;ai commité tel quel, mais quand j&amp;rsquo;ai changé de branche, le commit a disparu !&lt;/p>
&lt;h3 id="le-mécanisme-du-detached-head">Le mécanisme du Detached HEAD
&lt;/h3>&lt;p>Normalement, &lt;code>HEAD&lt;/code> pointe vers une branche comme &lt;code>refs/heads/main&lt;/code>. Cependant, si vous extrayez directement un commit spécifique, &lt;code>HEAD&lt;/code> pointera directement vers l&amp;rsquo;objet commit. C&amp;rsquo;est ce qu&amp;rsquo;on appelle un &lt;strong>Detached HEAD (HEAD détaché)&lt;/strong>.&lt;/p>
&lt;pre class="mermaid">
graph TD
A[&amp;#34;Commit A&amp;#34;] --&amp;gt; B[&amp;#34;Commit B&amp;#34;]
B --&amp;gt; C[&amp;#34;Commit C&amp;#34;]
C --&amp;gt; D[&amp;#34;Commit D&amp;#34;]
BranchMain[&amp;#34;Branche : main&amp;#34;] --&amp;gt; D
HEAD[&amp;#34;HEAD&amp;#34;] --&amp;gt; B
style HEAD fill:#f9f,stroke:#333,stroke-width:4px
&lt;/pre>
&lt;p>Même si vous empilez les commits dans cet état, aucune branche ne suivra ces nouveaux commits. Au moment où vous passez à une autre branche, les nouveaux commits se perdent.&lt;/p>
&lt;h3 id="solution--sauvegarder-en-tant-que-nouvelle-branche">Solution : Sauvegarder en tant que nouvelle branche
&lt;/h3>&lt;p>Le problème est résolu en créant une nouvelle branche à l&amp;rsquo;endroit où vous vous trouvez actuellement.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Créer une nouvelle branche à la position actuelle de HEAD et basculer dessus&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git checkout -b feature/recovered-work
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;hr>
&lt;h2 id="8-étude-de-cas-5--résolution-de-conflits-lors-de-merge-et-rebase">8. Étude de cas 5 : Résolution de conflits lors de Merge et Rebase
&lt;/h2>&lt;p>&lt;strong>【Situation】&lt;/strong>
J&amp;rsquo;ai exécuté &lt;code>git merge&lt;/code> ou &lt;code>git rebase&lt;/code>, et &lt;code>CONFLICT (content)&lt;/code> s&amp;rsquo;est affiché, le processus a été interrompu.&lt;/p>
&lt;h3 id="différence-entre-merge-fusion-et-rebase-rebasage">Différence entre Merge (fusion) et Rebase (rebasage)
&lt;/h3>&lt;ol>
&lt;li>&lt;strong>Merge (fusion)&lt;/strong>
Effectue une fusion à 3 voies (3-way merge) en utilisant le dernier commit de deux branches et leur ancêtre commun, et crée un commit de fusion.&lt;/li>
&lt;li>&lt;strong>Rebase (rebasage)&lt;/strong>
Enregistre temporairement les commits de la branche actuelle et les réapplique à la pointe de la branche cible. L&amp;rsquo;historique devient une ligne droite.&lt;/li>
&lt;/ol>
&lt;pre class="mermaid">
gitGraph
commit id: &amp;#34;M1&amp;#34;
commit id: &amp;#34;M2&amp;#34;
branch feature
checkout feature
commit id: &amp;#34;F1&amp;#34;
commit id: &amp;#34;F2&amp;#34;
checkout main
commit id: &amp;#34;M3&amp;#34;
merge feature
&lt;/pre>
&lt;h3 id="comment-résoudre-un-conflit">Comment résoudre un conflit
&lt;/h3>&lt;p>Les marqueurs suivants sont insérés dans les fichiers où des conflits se sont produits.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&lt;/span> &lt;span class="nx">HEAD&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">apiUrl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://api.production.example.com&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">=======&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">apiUrl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="s2">&amp;#34;https://api.staging.example.com&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="o">&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span> &lt;span class="nx">feature&lt;/span>&lt;span class="o">/&lt;/span>&lt;span class="k">new&lt;/span>&lt;span class="o">-&lt;/span>&lt;span class="nx">api&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>La procédure de résolution est extrêmement simple.&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Supprimez les marqueurs et corrigez avec le bon code.&lt;/strong>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-javascript" data-lang="javascript">&lt;span class="line">&lt;span class="cl">&lt;span class="kr">const&lt;/span> &lt;span class="nx">apiUrl&lt;/span> &lt;span class="o">=&lt;/span> &lt;span class="nx">process&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">env&lt;/span>&lt;span class="p">.&lt;/span>&lt;span class="nx">NODE_ENV&lt;/span> &lt;span class="o">===&lt;/span> &lt;span class="s1">&amp;#39;production&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">?&lt;/span> &lt;span class="s2">&amp;#34;https://api.production.example.com&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl"> &lt;span class="o">:&lt;/span> &lt;span class="s2">&amp;#34;https://api.staging.example.com&amp;#34;&lt;/span>&lt;span class="p">;&lt;/span>
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>&lt;strong>Ajoutez le fichier résolu à l&amp;rsquo;index (staging).&lt;/strong>
&lt;code>git add&lt;/code> a pour rôle de &amp;ldquo;dire à Git que le conflit est résolu&amp;rdquo;.
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">$ git add index.js
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;li>&lt;strong>Terminez le processus.&lt;/strong>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;span class="lnt">4
&lt;/span>&lt;span class="lnt">5
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Dans le cas d&amp;#39;un merge&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git commit -m &lt;span class="s2">&amp;#34;Resolve merge conflict in index.js&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Dans le cas d&amp;#39;un rebase&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git rebase --continue
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;/li>
&lt;/ol>
&lt;p>Si vous paniquez, vous pouvez toujours annuler avec &lt;code>$ git merge --abort&lt;/code> ou &lt;code>$ git rebase --abort&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="9-étude-de-cas-6--lhistorique-des-commits-est-un-gâchis--git-rebase--i">9. Étude de cas 6 : L&amp;rsquo;historique des commits est un gâchis ! &lt;code>git rebase -i&lt;/code>
&lt;/h2>&lt;p>&lt;strong>【Situation】&lt;/strong>
Un grand nombre de petits commits tels que &amp;ldquo;Correction de typo&amp;rdquo;, &amp;ldquo;Encore une correction&amp;rdquo;, &amp;ldquo;Ajout de tests&amp;rdquo; ont été générés. Si je fusionne dans &lt;code>main&lt;/code> tel quel, l&amp;rsquo;historique sera sale.&lt;/p>
&lt;h3 id="solution--rebase-interactif">Solution : Rebase interactif
&lt;/h3>&lt;p>En utilisant &lt;code>git rebase -i&lt;/code> (interactif), vous pouvez modifier l&amp;rsquo;ordre des commits passés, combiner plusieurs commits en un seul (squash), ou modifier les messages de commit.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Organiser les 3 derniers commits&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git rebase -i HEAD~3
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>L&amp;rsquo;éditeur s&amp;rsquo;ouvrira et affichera ceci :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">pick 1a2b3c4 Correction de typo
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pick 2b3c4d5 Encore une correction
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">pick 3c4d5e6 Ajout de tests
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Réécrivez-le comme ceci :&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="cl">pick 1a2b3c4 Implémentation de la fonctionnalité X
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">squash 2b3c4d5 Encore une correction
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">squash 3c4d5e6 Ajout de tests
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>Enregistrez et fermez, ces 3 commits seront magnifiquement fusionnés en un seul.&lt;/p>
&lt;hr>
&lt;h2 id="10-étude-de-cas-7--je-ne-sais-pas-quand-le-bug-a-été-introduit--git-bisect">10. Étude de cas 7 : Je ne sais pas quand le bug a été introduit ! &lt;code>git bisect&lt;/code>
&lt;/h2>&lt;p>&lt;strong>【Situation】&lt;/strong>
La branche &lt;code>main&lt;/code> actuelle a un bug, mais tout était normal lors de la version d&amp;rsquo;il y a un mois. Je veux identifier dans quel commit le bug a été introduit, mais il y a plus de 100 commits et c&amp;rsquo;est impossible de le faire manuellement !&lt;/p>
&lt;h3 id="solution--identifier-le-bug-par-recherche-dichotomique">Solution : Identifier le bug par recherche dichotomique
&lt;/h3>&lt;p>Git intègre un outil pour trouver le commit qui a introduit un bug en utilisant la recherche dichotomique (Binary Search) mathématique. La complexité de calcul étant de $\mathcal{O}(\log N)$, même s&amp;rsquo;il y a 1000 commits, vous pouvez l&amp;rsquo;identifier en environ 10 tests.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt"> 1
&lt;/span>&lt;span class="lnt"> 2
&lt;/span>&lt;span class="lnt"> 3
&lt;/span>&lt;span class="lnt"> 4
&lt;/span>&lt;span class="lnt"> 5
&lt;/span>&lt;span class="lnt"> 6
&lt;/span>&lt;span class="lnt"> 7
&lt;/span>&lt;span class="lnt"> 8
&lt;/span>&lt;span class="lnt"> 9
&lt;/span>&lt;span class="lnt">10
&lt;/span>&lt;span class="lnt">11
&lt;/span>&lt;span class="lnt">12
&lt;/span>&lt;span class="lnt">13
&lt;/span>&lt;span class="lnt">14
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Démarrer la recherche&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git bisect start
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Le commit actuel a un bug (bad)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git bisect bad
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Il y a un mois (par exemple le hachage a1b2c3d) c&amp;#39;était normal (good)&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git bisect good a1b2c3d
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Git extrait automatiquement un commit intermédiaire, vous exécutez donc le test&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Si le test réussit :&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git bisect good
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">&lt;span class="c1"># Si le test échoue :&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">$ git bisect bad
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;p>En répétant simplement cela, Git vous dira exactement : &amp;ldquo;Ce commit est le premier commit Bad&amp;rdquo;. Une fois terminé, revenez à l&amp;rsquo;état d&amp;rsquo;origine avec &lt;code>$ git bisect reset&lt;/code>.&lt;/p>
&lt;hr>
&lt;h2 id="11-le-filet-de-sécurité-ultime--git-reflog">11. Le filet de sécurité ultime : &lt;code>git reflog&lt;/code>
&lt;/h2>&lt;p>La technique secrète ultime pour toutes les &amp;ldquo;gaffes&amp;rdquo; sur Git est &lt;code>git reflog&lt;/code>. Git enregistre tout l&amp;rsquo;historique des opérations locales (l&amp;rsquo;historique des déplacements de HEAD) pendant une certaine période. Même si vous supprimez une branche ou effectuez une mauvaise réinitialisation, vous pouvez toujours récupérer en trouvant le hachage passé avec &lt;code>git reflog&lt;/code> et en effectuant un &lt;code>git reset --hard&lt;/code> dessus.&lt;/p>
&lt;div class="highlight">&lt;div class="chroma">
&lt;table class="lntable">&lt;tr>&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code>&lt;span class="lnt">1
&lt;/span>&lt;span class="lnt">2
&lt;/span>&lt;span class="lnt">3
&lt;/span>&lt;/code>&lt;/pre>&lt;/td>
&lt;td class="lntd">
&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="cl">$ git reflog
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">9f8a7b6 &lt;span class="o">(&lt;/span>HEAD -&amp;gt; main&lt;span class="o">)&lt;/span> HEAD@&lt;span class="o">{&lt;/span>0&lt;span class="o">}&lt;/span>: commit: Add new feature
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="cl">1a2b3c4 HEAD@&lt;span class="o">{&lt;/span>1&lt;span class="o">}&lt;/span>: reset: moving to HEAD~1
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/td>&lt;/tr>&lt;/table>
&lt;/div>
&lt;/div>&lt;h2 id="12-conclusion">12. Conclusion
&lt;/h2>&lt;p>Nous avons expliqué très en détail les erreurs courantes dans lesquelles tombent les débutants sur Git, les mécanismes de Git en arrière-plan et comment les résoudre. Commiter sur la mauvaise branche, annuler un commit déjà poussé, utiliser Stash, survivre à un Detached HEAD et résoudre des conflits. Ce qui est important dans tout cela, c&amp;rsquo;est d&amp;rsquo;imaginer &amp;ldquo;quels objets et pointeurs Git manipule en arrière-plan&amp;rdquo;.&lt;/p>
&lt;p>Les différences de fichiers sont calculées par un algorithme Diff strict représenté par des formules mathématiques, et la cohérence de l&amp;rsquo;historique est garantie par des fonctions de hachage cryptographiques. Si vous comprenez cette belle philosophie de conception, vous devriez réaliser que Git n&amp;rsquo;est en aucun cas une &amp;ldquo;boîte noire mystérieuse&amp;rdquo;, mais le bouclier le plus puissant pour protéger fermement votre code source.&lt;/p>
&lt;p>La prochaine fois que vous penserez &amp;ldquo;J&amp;rsquo;ai gaffé !&amp;rdquo;, ne fermez pas le terminal dans la panique, prenez une grande respiration et tapez &lt;code>git status&lt;/code>. Git vous donnera toujours des indices pour la récupération.&lt;/p></description></item></channel></rss>