Pourquoi le staging granulaire est important
Un historique Git bien construit raconte une histoire. Chaque commit représente un changement logique unique : une correction de bug, un refactoring, une nouvelle fonctionnalité. Mais le développement réel est rarement aussi ordonné. Vous corrigez un bug, puis remarquez une faute de frappe à côté, puis ajustez du formatage, puis commencez un petit refactoring -- le tout dans le même fichier. Si vous mettez en staging et commitez le fichier entier d'un coup, vous vous retrouvez avec un commit qui mélange des changements sans rapport. Cela rend la revue de code plus difficile, rend la recherche de bugs avec bisect plus difficile, et rend l'historique des commits moins utile comme documentation.
Le staging granulaire vous permet de découper votre travail en commits significatifs, même lorsque les changements sont entrelacés dans le même fichier. Au lieu de tout commiter d'un coup, vous choisissez exactement quels changements vont ensemble.
Trois niveaux de staging
Staging au niveau fichier
Le niveau le plus basique. Vous mettez en staging des fichiers entiers avec git add :
git add src/auth.ts src/utils.ts
C'est suffisant quand chaque fichier contient un seul changement logique. Mais dès qu'un fichier contient plusieurs modifications sans rapport, le staging au niveau fichier est trop grossier.
Staging au niveau hunk
Git peut découper les changements d'un fichier en "hunks" -- des blocs contigus de lignes modifiées séparés par du code inchangé. Avec git add -p (mode patch), Git présente chaque hunk un par un et demande s'il faut le mettre en staging :
git add -p src/auth.ts
Pour chaque hunk, vous choisissez y (stager), n (passer), s (découper en hunks plus petits), ou e (éditer manuellement). C'est une amélioration majeure par rapport au staging au niveau fichier, mais cela a des limites. Les hunks sont définis par la proximité : si deux changements sans rapport sont proches (séparés par moins de trois lignes de contexte), Git les regroupe en un seul hunk. Les séparer nécessite l'édition manuelle de patch, ce qui est fastidieux et sujet aux erreurs.
Staging au niveau ligne
Le staging au niveau ligne est l'option la plus précise. Au lieu de travailler avec des fichiers ou des hunks, vous sélectionnez des lignes individuelles à stager. Vous voulez stager les lignes 12 et 15 mais pas la ligne 14 ? C'est possible. Cela vous donne un contrôle complet sur ce qui entre dans chaque commit, quelle que soit la proximité des changements dans le fichier.
En ligne de commande, le staging au niveau ligne signifie éditer manuellement des patches avec git add -p et l'option e. Vous devez comprendre le format unified diff, modifier soigneusement le patch, et espérer ne pas introduire d'erreurs. Ça fonctionne, mais ce n'est pas quelque chose que la plupart des développeurs veulent faire régulièrement.
Staging au niveau ligne dans GitSquid
GitSquid rend le staging au niveau ligne visuel et simple. Quand vous sélectionnez un fichier modifié, le visualiseur de diff affiche chaque ligne modifiée. Pour stager des lignes spécifiques :
- Cliquez sur une seule ligne pour la sélectionner.
- Cmd+Click (Ctrl+Click sur Windows/Linux) pour sélectionner plusieurs lignes individuelles.
- Shift+Click pour sélectionner une plage de lignes.
Une fois que vous avez sélectionné les lignes souhaitées, mettez-les en staging. Seules ces lignes sont ajoutées à l'index. Le reste demeure comme modifications non stagées dans votre répertoire de travail, prêt à être inclus dans un commit différent.
Le même workflow fonctionne en sens inverse. Si vous avez déjà stagé des lignes que vous voulez retirer de la zone de staging, vous pouvez les sélectionner dans le diff stagé et ne déstaguer que ces lignes.
Comment ça fonctionne sous le capot
Quand vous stagez des lignes individuelles, GitSquid génère un patch côté serveur qui inclut uniquement les changements sélectionnés. Ce patch est ensuite appliqué à l'index en utilisant le mécanisme de patch de Git. En gérant la génération du patch côté serveur plutôt qu'en manipulant le diff côté client, le résultat est fiable et correspond exactement à ce que Git attend. Il n'y a pas de problèmes de formatage ou d'erreurs de décalage que vous pourriez rencontrer en éditant des patches à la main.
Exemples pratiques
Séparer une correction de bug d'un refactoring
Vous travaillez sur un refactoring et remarquez un bug. Vous le corrigez immédiatement parce que la correction est évidente. Maintenant votre fichier contient deux types de changements : le refactoring et la correction de bug. Avec le staging au niveau ligne, vous sélectionnez uniquement les lignes de la correction de bug, les commitez avec un message clair comme "fix null check in auth validation", puis commitez le refactoring séparément. Le résultat est deux commits propres et faciles à relire au lieu d'un seul confus.
Séparer le code de debug du code de production
Vous avez ajouté des instructions console.log pendant le débogage, juste à côté des changements réels du code. Au lieu d'essayer de vous rappeler quelles lignes sont du debug et lesquelles sont réelles, vous sélectionnez visuellement uniquement les changements de production, les stagez et commitez. Les lignes de debug restent dans votre répertoire de travail où vous pouvez continuer à les utiliser ou les supprimer plus tard.
Préparer un commit partiel pour la revue
Vous avez un grand ensemble de changements, mais seule une partie du travail est prête pour la revue. Le staging au niveau ligne vous permet de commiter les parties terminées tout en gardant le code en cours de développement non commité. Votre pull request reste ciblée, et le relecteur n'a pas à parcourir du code incomplet.
Garder des commits atomiques
Un commit atomique est celui qui contient un seul changement logique et complet. Il passe les tests, ne casse pas le build, et peut être compris indépendamment. Les commits atomiques ne sont pas qu'une question d'ordre. Ils ont des avantages pratiques :
- Revue de code. Les relecteurs peuvent comprendre chaque commit indépendamment. Un commit intitulé "fix input validation" qui ne touche que la logique de validation est facile à relire. Un commit intitulé "various changes" qui touche la validation, le style et la configuration ne l'est pas.
- Chasse aux bugs. Quand quelque chose casse,
git bisectpeut identifier le commit exact qui a introduit le problème. Les commits atomiques rendent le résultat significatif : vous trouvez le changement spécifique qui a causé le bug, pas un fourre-tout de modifications sans rapport. - Revert. Si un commit doit être reverté, un commit atomique peut être reverté proprement. Un commit mixte pourrait vous forcer à reverter des changements que vous vouliez en fait garder.
- L'historique comme documentation. Des mois plus tard, quand quelqu'un lit l'historique des commits pour comprendre pourquoi un morceau de code existe, les commits atomiques avec des messages clairs racontent une histoire utile.
Le staging au niveau ligne est l'outil qui rend les commits atomiques pratiques. Sans lui, créer des commits propres à partir d'un développement réel désordonné demande de la discipline et des efforts manuels. Avec lui, le processus est aussi simple que de sélectionner les lignes qui vont ensemble.
Les meilleurs commits sont ceux qui font exactement une chose. Le staging granulaire vous donne le contrôle pour y parvenir, même quand votre répertoire de travail raconte une histoire différente.