Accéder au contenu principal

Git Squash Commits : Un guide avec des exemples

Apprenez à écraser les livraisons sur une branche à l'aide du rebasement interactif, ce qui permet de conserver un historique des livraisons propre et organisé.
Actualisé 14 févr. 2025  · 7 min de lecture

"Commit early, commit often" est un mantra populaire dans le domaine du développement logiciel lorsque l'on utilise Git. Le cursus permet de s'assurer que chaque modification est bien documentée, d'améliorer la collaboration et de faciliter le suivi de l'évolution du projet. Toutefois, cela peut également conduire à une surabondance de commits.

C'est là qu'intervient l'importance d'écraser les commits. L'écrasement des livraisons est le processus qui consiste à combiner plusieurs livraisons en une seule, cohérente.

Devenez ingénieur en données

Devenez un ingénieur de données grâce à l'apprentissage avancé de Python
Commencez à apprendre gratuitement

Par exemple, disons que nous travaillons sur une fonctionnalité mettant en œuvre un formulaire de connexion, et que nous créons les quatre commits suivants :

Exemple d'historique des livraisons Git

Une fois la fonctionnalité achevée, ces commits sont trop détaillés pour l'ensemble du projet. Nous n'avons pas besoin de savoir à l'avenir que nous avons rencontré un bogue qui a été corrigé pendant le développement. Afin d'assurer un historique propre dans la branche principale, nous écrasons ces commits en un seul commit :

Exemple d'écrasement de commits Git

Comment écraser les commits dans Git : Rebase interactif

La méthode la plus courante pour écraser les commits consiste à utiliser un rebasement interactif. Nous le démarrons à l'aide de la commande :

git rebase -i HEAD~<number_of_commits>

Remplacez par le nombre de commits que nous voulons écraser.

Dans notre cas, nous avons quatre commits, la commande est donc la suivante :

git rebase -i HEAD~4

L'exécution de cette commande ouvrira un éditeur de ligne de commande interactif :

Editeur CLI après git rebase -i

La partie supérieure affiche les commits, tandis que la partie inférieure contient des commentaires sur la façon d'écraser les commits.

Nous avons quatre engagements. Pour chacun d'entre eux, nous devons décider de la commande à exécuter. Nous nous intéressons aux commandes pick (p) et squash (s). Pour écraser ces quatre commits en un seul, nous pouvons choisir le premier et écraser les trois autres.

Nous appliquons les commandes en modifiant le texte précédant chaque livraison, en particulier en remplaçant pick par s ou squash pour les deuxième, troisième et quatrième livraisons. Pour effectuer ces modifications, nous devons passer en mode "INSERT" dans l'éditeur de texte en ligne de commande en appuyant sur la touche i du clavier :

Entrez en mode insertion dans l'éditeur CLI

Après avoir appuyé sur i, le texte -- INSERT -- apparaîtra en bas, indiquant que nous sommes entrés dans le mode insertion. Nous pouvons maintenant déplacer le curseur à l'aide des touches fléchées, supprimer des caractères et taper comme nous le ferions dans un éditeur de texte standard :

Interagir avec l'éditeur de texte CLI

Une fois que nous sommes satisfaits des modifications, nous devons quitter le mode insertion en appuyant sur la touche Esc du clavier. L'étape suivante consiste à enregistrer nos modifications et à quitter l'éditeur. Pour ce faire, nous appuyons d'abord sur la touche : pour signaler à l'éditeur que nous avons l'intention d'exécuter une commande :

Entrez une commande dans l'éditeur de texte de l'ITC

En bas de l'éditeur, nous voyons maintenant un point-virgule : qui nous invite à insérer une commande. Pour enregistrer les modifications, nous utilisons la commande w, qui signifie "écrire". Pour fermer l'éditeur, utilisez q, qui signifie "quitter". Ces commandes peuvent être combinées et tapées ensemble wq:

Comment sauvegarder et quitter l'éditeur de texte CLI

Pour exécuter la commande, nous appuyons sur la touche Enter. Cette action fermera l'éditeur actuel et en ouvrira un nouveau, ce qui nous permettra de saisir le message de validation pour la nouvelle validation écrasée. L'éditeur affichera un message par défaut comprenant les messages des quatre commits que nous écrasons :

Modification du message de validation de la courge

Je vous recommande de modifier le message afin de refléter correctement les modifications apportées par ces commits combinés - après tout, l'objectif de l'écrasement est de maintenir un historique propre et facilement lisible. 

Pour interagir avec l'éditeur et modifier le message, appuyez à nouveau sur i pour passer en mode édition et modifier le message à votre convenance.

Exemple de message de validation Squash

Dans ce cas, nous remplaçons le message de validation par "Implement login form". Pour quitter le mode édition, appuyez sur Esc. Sauvegardez ensuite les modifications en appuyant sur :, en saisissant la commande wq et en appuyant sur Enter.

Comment consulter l'historique des engagements

En règle générale, il peut être difficile de se souvenir de l'ensemble de l'historique des livraisons. Pour consulter l'historique des livraisons, vous pouvez utiliser la commande git log. Dans l'exemple mentionné, avant d'effectuer le squash, l'exécution de la commande git log afficherait :

Historique des livraisons du journal Git avant le squash

Pour naviguer dans la liste des commits, utilisez les touches fléchées vers le haut et vers le bas. Pour quitter, appuyez sur q.

Nous pouvons utiliser git log pour confirmer le succès de la courge. Si vous l'exécutez après le squash, vous obtiendrez un seul commit avec le nouveau message :

Historique des livraisons du journal Git après le squash

Pousser un commit écrasé

La commande ci-dessus agit sur le référentiel local. Pour mettre à jour le référentiel distant, nous devons pousser nos modifications. Cependant, comme nous avons modifié l'historique des livraisons, nous devons forcer la poussée en utilisant l'option --force:

git push --force origin feature/login-form

Forcer la poussée écrasera l'historique des livraisons sur la branche distante et perturbera potentiellement les autres personnes travaillant sur cette branche. Il est conseillé de communiquer avec l'équipe avant de procéder à cette opération.

Un moyen plus sûr de forcer la poussée, qui réduit le risque de perturber les collaborateurs, consiste à utiliser l'option --force-with-lease:

git push --force-with-lease origin feature/login-form

Cette option assure que nous ne forçons le push que si la branche distante n'a pas été mise à jour depuis notre dernier fetch ou pull.

Ecraser des commits spécifiques

Imaginez que nous ayons cinq candidats :

Exemple de journal Git avec cinq commits

Supposons que nous voulions conserver les commits 1, 2 et 5 et remplacer les commits 3 et 4.

Ecraser un commit

Lorsque vous utilisez le rebasement interactif, les commits marqués pour l'écrasement seront combinés avec le commit qui les précède directement. Dans ce cas, cela signifie que nous voulons écraser Commit4 pour qu'il fusionne avec Commit3.

Pour ce faire, nous devons initier un rebasement interactif qui inclut ces deux commits. Dans ce cas, trois commits suffisent, nous utilisons donc la commande :

git rebase -i HEAD~3

Ensuite, nous définissons Commit4 sur s de manière à ce qu'il soit écrasé par Commit3:

Exemple d'engagement de Squash two

Après avoir exécuté cette commande et listé les commits, nous observons que les commits 3 et 4 ont été écrasés ensemble alors que les autres restent inchangés.

Journal Git après l'écrasement

Squashing à partir d'un commit spécifique

Dans la commande git rebase -i HEAD~3, la partie HEAD est une abréviation de la dernière livraison. La syntaxe ~3 est utilisée pour spécifier l'ancêtre d'un commit. Par exemple, HEAD~1 fait référence au parent de l'engagement HEAD.

Illustration de la notation ~

Dans un rebasement interactif, les commits pris en compte comprennent tous les commits ancestraux précédant le commit spécifié dans la commande. Notez que le commit spécifié n'est pas inclus :

Comment les modifications sont-elles incluses dans un rebasement interactif ?

Au lieu d'utiliser HEAD, nous pouvons spécifier un hachage de livraison directement. Par exemple, Commit2 a un hash de dbf3cc118d6d7c08ef9c4a326b26dbb1e3fe9ddf, donc la commande :

git rebase -i dbf3cc118d6d7c08ef9c4a326b26dbb1e3fe9ddf

commencerait un rebase en prenant en compte tous les commits effectués après Commit2. Par conséquent, si nous voulons lancer un rebase à un commit spécifique et inclure ce commit, nous pouvons utiliser la commande :

git rebase -i <commit-hash>~1

Résoudre les conflits lors de l'écrasement de Commits

Lorsque nous regroupons des commits, nous combinons plusieurs modifications en un seul commit, ce qui peut entraîner des conflits si les modifications se chevauchent ou divergent de manière significative. Voici quelques scénarios courants dans lesquels des conflits peuvent survenir :

  1. Chevauchement des changements: Si deux ou plusieurs commits à écraser ont modifié les mêmes lignes d'un fichier ou des lignes très proches, Git peut ne pas être en mesure de réconcilier automatiquement ces changements. 
  2. Différents changements d'état: Si un commit ajoute un certain morceau de code et qu'un autre commit modifie ou supprime ce même morceau de code, l'écrasement de ces commits peut conduire à des conflits qui doivent être résolus.
  3. Renommer et modifier: Si un commit renomme un fichier et que les commits suivants apportent des modifications à l'ancien nom, l'écrasement de ces commits peut perturber Git et provoquer un conflit.
  4. Modifications apportées aux fichiers binaires: Les fichiers binaires ne fusionnent pas bien avec les outils de comparaison basés sur le texte. Si plusieurs commits modifient le même fichier binaire et que nous essayons de les écraser, un conflit peut survenir car Git ne peut pas réconcilier automatiquement ces changements.
  5. Histoire complexe: Si les commits ont un historique complexe avec de multiples fusions, ramifications ou rebases, les écraser peut entraîner des conflits en raison de la nature non linéaire des changements.

Lors de l'écrasement, Git tentera d'appliquer chaque changement un par un. S'il rencontre des conflits au cours du processus, il fera une pause et nous permettra de les résoudre. 

Les conflits seront marqués par les marqueurs de conflit <<<<<< et >>>>>>. Pour gérer les conflits, nous devons ouvrir les fichiers et résoudre manuellement chacun d'entre eux en sélectionnant la partie du code que nous voulons conserver. 

Après avoir résolu les conflits, nous devons mettre en scène les fichiers résolus à l'aide de la commande git add. Nous pouvons ensuite poursuivre le rebasement à l'aide de la commande suivante :

git rebase --continue

Pour en savoir plus sur les conflits Git, consultez ce tutoriel sur comment résoudre les conflits de fusion dans Git.

Alternatives à l'écrasement avec Rebase

La commande git merge --squash est une méthode alternative à git rebase -i pour combiner plusieurs livraisons en une seule. Cette commande est particulièrement utile lorsque nous voulons fusionner les modifications d'une branche dans la branche principale tout en écrasant tous les commentaires individuels en un seul. Voici une vue d'ensemble de l'utilisation de l'écrasement à l'aide de git merge:

  1. Nous naviguons vers la branche cible dans laquelle nous voulons incorporer les modifications.
  2. Nous exécutons la commande git merge --squash en remplaçant par le nom de la branche.
  3. Nous validons les modifications avec git commit pour créer une validation unique qui représente toutes les modifications de la branche de fonctionnalité.

Par exemple, supposons que nous voulions incorporer les modifications de la branche feature/login-form dans main en un seul commit :

git checkout main
git merge --squash feature-branch
git commit -m "Implement login form"

Telles sont les limites de cette approche par rapport à git rebase -i:

  • Granularité du contrôle : Moins de contrôle sur les engagements individuels. Avec rebase, nous pouvons choisir les commits à fusionner alors que merge force à combiner tous les changements en un seul commit.
  • Histoire intermédiaire : Lorsque vous utilisez la fusion, l'historique des livraisons individuelles de la branche des fonctionnalités est perdu dans la branche principale. Cela peut rendre plus difficile le cursus des modifications incrémentales apportées au cours du développement de la fonctionnalité.
  • Examen préalable à l'engagement : Puisqu'il met en scène tous les changements comme un seul ensemble de changements, nous ne pouvons pas examiner ou tester chaque livraison individuellement avant l'écrasement, contrairement à un rebasement interactif où chaque livraison peut être examinée et testée dans l'ordre.

Conclusion

Le fait d'intégrer de petites modifications fréquentes dans le processus de développement favorise la collaboration et la clarté de la documentation, mais cela peut également encombrer l'historique du projet. L'écrasement des commits permet de trouver un équilibre, en préservant les étapes importantes tout en éliminant le bruit des changements itératifs mineurs.

Pour en savoir plus sur Git, je vous recommande les ressources suivantes :


François Aubry's photo
Author
François Aubry
LinkedIn
L'enseignement a toujours été ma passion. Dès mes premiers jours d'études, j'ai cherché avec enthousiasme des occasions de donner des cours particuliers et d'aider d'autres étudiants. Cette passion m'a amenée à poursuivre un doctorat, où j'ai également été assistante d'enseignement pour soutenir mes efforts académiques. Au cours de ces années, j'ai trouvé un immense épanouissement dans le cadre d'une classe traditionnelle, en favorisant les liens et en facilitant l'apprentissage. Cependant, avec l'avènement des plateformes d'apprentissage en ligne, j'ai reconnu le potentiel de transformation de l'éducation numérique. En fait, j'ai participé activement au développement d'une telle plateforme dans notre université. Je suis profondément engagée dans l'intégration des principes d'enseignement traditionnels avec des méthodologies numériques innovantes. Ma passion est de créer des cours qui sont non seulement attrayants et instructifs, mais aussi accessibles aux apprenants à l'ère du numérique.
Sujets

Apprenez l'ingénierie des données avec ces cours !

cursus

Ingénieur de données associé

30 heures hr
Apprenez les fondamentaux de l'ingénierie des données : conception de bases de données et entreposage de données, en travaillant avec des technologies telles que PostgreSQL et Snowflake !
Afficher les détailsRight Arrow
Commencer le cours
Certification disponible

cours

Comprendre l'ingénierie des données

2 hr
246.8K
Découvrez comment les ingénieurs de données posent les bases qui rendent possible la science des données. Aucun codage n'est nécessaire !
Voir plusRight Arrow