cursus
Git Squash Commits : Un guide avec des exemples
"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
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 :
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 :
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 :
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 :
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 :
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 :
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
:
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 :
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.
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 :
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 :
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 :
Supposons que nous voulions conserver les commits 1, 2 et 5 et remplacer les commits 3 et 4.
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
:
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.
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
.
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 :
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 :
- 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.
- 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.
- 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.
- 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.
- 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
:
- Nous naviguons vers la branche cible dans laquelle nous voulons incorporer les modifications.
- Nous exécutons la commande
git merge --squash
en remplaçantpar le nom de la branche.
- 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 :
Apprenez l'ingénierie des données avec ces cours !
cursus
Ingénieur professionnel en données
cours