Git add hero đ€
Par Maxime Bréhin ⹠Publié le 12 janvier 2022
âą 7 min
Lorsquâon dĂ©bute avec Git, une des premiĂšres commandes quâon utilise est git add
. Elle est essentielle Ă une bonne utilisation de Git puisquâelle nous permet de prĂ©parer nos commits. Elle nâest pourtant jamais vraiment apprise, ce qui est regrettable car elle nous offre des options trĂšs pratiques !
Pour bien comprendre cet article, il est important dâavoir dĂ©jĂ assimilĂ© la notion de zones Git. Et comme on aime faire les choses bien, on a Ă©crit un article Ă ce sujet.
Vous préférez une vidéo ?
Si vous ĂȘtes du genre Ă prĂ©fĂ©rer regarder que lire pour apprendre, on a pensĂ© Ă vous :
Principe de fonctionnement
Lorsquâon fait un git add âŠ
on demande Ă Git dâenregistrer dans le stage les fichiers quâon souhaitera plus tard valider (intĂ©gration au commit). En dâautres termes, on ajoute, modifie, supprime des fichiers dans notre copie de travail et on signale Ă Git que tout ou partie de ces modifications est Ă mettre dans un statut intermĂ©diaire (staged) avant dâĂȘtre validĂ© sous la forme dâun commit.
On a donc la possibilitĂ© de prĂ©ciser des chemins complets ou partiels (globs) et ne prendre quâune partie des modifications rĂ©alisĂ©es dans notre copie de travail (working directory) en vue dâun commit prochain.
Si la technique vous intéresse, voici ce qui se passe sous le capot :
- Pour chaque fichier, un « instantané » du contenu est capturé :
- il ne stocke pas les diffĂ©rences mais bien lâintĂ©gralitĂ© du fichier dans sa nouvelle version ;
- ce fichier est optimisé pour stockage sur le disque et appelé blob (pour Binary Large Object) ;
- le nom de ce fichier est une empreinte basée sur le contenu du fichier (hash de type SHA-1 ou SHA-2) ;
- ce fichier est stocké dans le répertoire
.git/objects
.
- Les références aux fichiers sont enregistrées dans le stage (fichier
.git/index
).
Utilisation « classique »
Que vous soyez dans un terminal ou dans un Ă©diteur muni dâune interface Git, vous aurez accĂšs aux utilisations les plus frĂ©quentes de la commande add
, Ă savoir lâenregistrement des ajouts, modifications et suppressions des fichiers complets. Ceci Ă©quivaut en ligne de commande Ă passer le ou les chemins de fichiers concernĂ©s :
git add file-1 file-2
On peut aller bien plus loin et gagner en temps, en confort, en qualitĂ© en sâaidant de quelques options. Remarquez que certaines options ne sont parfois disponibles quâen ligne de commande. Ă vous de dĂ©terminer si votre Ă©diteur prĂ©fĂ©rĂ© sait gĂ©rer celles qui vous intĂ©ressent.
Notre sĂ©lection dâoptions utiles
<chemins>
(ou-- <chemins>
pour lever lâambiguĂŻtĂ© avec le double tiret POSIX) ;-u
/--update
, pour ne traiter que les fichiers déjà versionnés ;-A
/--all
/--no-ignore-removal
, la totale : ajouts, modifications, suppressions ;-f
/--force
pour forcer lâajout de fichiers normalement ignorĂ©s ;-p
/--patch
, pour ne stager quâune partie des modifications des fichiers ;-N
/--intent-to-add
pour permettre les diffs, leadd -p
et lecommit -a
des fichiers non-suivis.
Un petit tour des globs
Les (nombreuses) commandes Git capables de travailler avec des chemins de fichiers vous offrent la possibilitĂ© (en ligne de commande notamment) de passer des chemins exacts (fichiers ou rĂ©pertoires) voire des globs. Faisons un petit tour dâhorizon de ces usages :
# Fichiers
git add file-1 file-2 director-1/file-3
# RĂ©pertoires
git add director-1/ directory-2/sub-directory
# Le célÚbre « prend tout dans le dossier courant »
git add .
# Les globs ou motifs de chemins (ici : tous les fichiers dans le
# répertoire courant dont le nom commence par « file » et tous les
# fichiers dans tous les sous-répertoires ayant pour extension « .js »)
git add file* **/*.js
# Et bien évidemment on peut mélanger les syntaxes
git add file-1 dir-1/ *.md
Ces syntaxes sont utilisables pour la partie fichiers de lâappel, qui suit les options de git add
.
Tout sauf les nouveautés
Vous souhaiterez parfois nâintĂ©grer que les modifications et suppressions, donc tout sauf les fichiers nouvellement crĂ©Ă©s (qui ne sont pas encore versionnĂ©s). Pour ça, vous avez lâoption -u
/ --update
 :
Tout, partout !
Vous voudrez souvent prendre lâintĂ©gralitĂ© du travail en cours : ajouts, suppressions et modifications. On utilise en gĂ©nĂ©ral git add .
, mais si vous avez tendance à vous balader dans vos répertoires, ce .
ne désignant que le répertoire courant et ses sous-répertoires, vous pourriez manquer les répertoires parents.
Câest lĂ tout lâintĂ©rĂȘt dâemployer plutĂŽt git add --all
/ -A
 :
Cesse de mâignorer !
Si les fichiers que vous souhaitez ajouter font partie des fichiers habituellement ignorés par Git (voir le fonctionnement du .gitignore
), vous devrez alors forcer leur ajout avec lâoption --force
/ -f
. Une fois ces fichiers versionnĂ©s, leurs modifications ultĂ©rieures apparaitront au mĂȘme titre que pour les autres fichiers. Pour cesser de les versionner tout en les conservant sur disque, vous aurez besoin dâun git rm --cached
par exemple (notez quâils existeront toujours dans les commits qui les contenaient).
Pour illustrer cela, prenons le cas de figure récurrent des logs. Généralement les fichiers de logs sont placés dans un répertoire applicatif dédié, ici log/
, et on ne souhaite pas historiser les logs dans Git, ça nâa aucun intĂ©rĂȘt. On va alors indiquer dans le fichier .gitignore
quâon ne souhaite pas versionner les fichiers contenus dans ce rĂ©pertoire :
# On recourt Ă une astuce pour ajouter rapidement
# en fin de fichier la ligne « log/* ».
echo 'log/*' >> .gitignore
Si votre stack technique ne crĂ©e pas automatiquement son dossier de logs (et refuse de se lancer sâil nâexiste pas), vous devrez vous assurer quâil existe dâoffice, ce qui suppose que Git versionne le rĂ©pertoire. Sauf que Git ne gĂšre pas des rĂ©pertoires, seulement des fichiers. Pour palier à ça, lâastuce classique consiste Ă crĂ©er un fichier vide .keep
ou .git-keep
dans le répertoire ciblé :
# Crée un fichier vide « .keep » dans le répertoire « log ».
touch log/.keep
Le problĂšme, câest que ce fichier est ignorĂ©, il ne nous est pas proposĂ© Ă lâajout lors dâun git status
et git add
refusera de lâajouter â mais nous dira que nous pouvons forcer lâajout :
git add --force log/.keep
Et voilà , le tour est joué !
Lâajout chirurgical : « Docteur Patch »
Sâil y a une option quâon affectionne particuliĂšrement, câest bien le git add --patch
 ! Elle nous permet de choisir, au sein dâun fichier, les modifications quâon souhaite stager. Câest parfait quand on sâaperçoit quâon a travaillĂ© sur plusieurs aspects et quâon souhaite dĂ©couper tout ça pour obtenir plus de clartĂ© dans notre historique de commits.
Si on lâutilise sans paramĂštre supplĂ©mentaire, les fichiers nous seront proposĂ©s un Ă un avec un Ă©ventuel prĂ©-dĂ©coupage des fragments de modifications (appelĂ©s hunks) quand lâespacement entre ces blocs est assez consĂ©quent.
On peut là aussi passer des chemins ou globs pour ne proposer des découpes que sur les fichiers qui nous intéressent.
Lorsquâon a lancĂ© la commande, un assistant sâouvre et affiche ce qui ressemble Ă un git diff
. Cet affichage nous indique le nombre de fragments quâil a dĂ©coupĂ©s dans le fichier (dans lâexemple qui suit (1/2)
signifie quâon traite le premier bloc sur 2). Il nous pose ensuite une question avec tout plein de lettres entre crochets derriĂšre, qui nâest pas le truc le plus clair du monde :
(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,?]?
Heureusement, on peut renseigner le point dâinterrogation ?
puis valider pour obtenir davantage de précisions :
y - stage this hunk
n - do not stage this hunk
q - quit; do not stage this hunk or any of the remaining ones
a - stage this hunk and all later hunks in the file
d - do not stage this hunk or any of the later hunks in the file
g - select a hunk to go to
/ - search for a hunk matching the given regex
j - leave this hunk undecided, see next undecided hunk
J - leave this hunk undecided, see next hunk
s - split the current hunk into smaller hunks
e - manually edit the current hunk
? - print help
Notez que lâoption s
(split) nâest disponible que lorsque le fragment affichĂ© permet dâĂȘtre redĂ©coupĂ© facilement (quand il existe des lignes intactes entre les modifications du fragment courant).
Pour un usage courant, on utilisera principalement les options y
(pour valider le fragment) et n
(pour lâinverse). Parfois le s
quand la dĂ©coupe nâest pas assez fine Ă notre goĂ»t.
Il existe Ă©galement une option e
(edit) pour permettre la modification manuelle du fragment, ce qui revient à gérer à la main les +
et -
dâun diff. Câest tentant si on se trouve face Ă un fragment sans sĂ©paration, donc sans option s
disponible, et quâon souhaite dĂ©couper quand mĂȘme. Attention tout de mĂȘme, il est difficile de construire manuellement un fragment appropriĂ©, et ça donne souvent des rĂ©sultats inattendus. Mieux vaut alors reprendre votre fichier, retirer temporairement la partie du fragment que vous ne souhaitez pas ajouter, faire votre git add âŠ
puis remettre la portion retirée dans le fichier.
Voici un exemple dâutilisation qui produit 3 commits Ă partir dâun unique fichier modifiĂ© en plusieurs endroits, chaque commit Ă©tant dĂ©diĂ© Ă un sujet prĂ©cis.
Lâintention dâajout
Câest lâajout indĂ©cis, « à la normande » : je veux ajouter, mais pas vraiment ! đ” ??
Il sâagit ici de lâoption --intent-to-add
ou -N
.
Elle sâavĂšre pratique lorsquâon souhaite visualiser lâensemble des diffĂ©rences stagĂ©es, y compris les nouveaux fichiers. En dâautres termes : sans ajout ou intention dâajout, la commande git diff
ne nous permettra pas de voir le contenus des nouveaux fichiers. MĂȘme chose dâailleurs pour le git add -p
.
Dâautre part elle permet la prise en considĂ©ration des nouveaux fichiers (non suivi/untracked) en cas dâutilisation du raccourci de commande git commit -a âŠ
(qui Ă©quivaut Ă un git add -u
+ git commit
).
Lâajout interactif, la fausse bonne idĂ©e
Si vous avez ouvert un jour la documentation de git add
(pour les curieux·ses : git help add
), peut-ĂȘtre avez vous dĂ©couvert lâoption -i
/ --interactive
. Peut-ĂȘtre mĂȘme avez-vous osĂ© ouvrir cette boite de Pandore et dĂ©couvert le dĂ©mon qui sây cachait đż.
Contrairement Ă ce quâon pourrait croire dâelle, cette option ne nous simplifie pas la tĂąche dâajout en nous fournissant une interface sensationnelle. Bien au contraire, elle nous plonge dans une interface particuliĂšrement dĂ©routante.
Une petite démo vaut mieux que des mots :
Bien préparer ses commits
Vous lâaurez compris, la commande git add
ne nous contraint pas Ă un simple ajout en masse des modifications, et câest tant mieux ! Cela nous permet de prĂ©parer au mieux des commits atomiques đ€Ż, câest-Ă -dire traitant dâun sujet le plus prĂ©cisemment possible, et, par consĂ©quent, de produire un historique clair et utile.
Si vous voulez creuser plus ce sujet, nous vous recommandons de parcourir notre sĂ©rie dâarticles sur lâutilisation de Git pour assister et automatiser la qualitĂ© des commits dans nos projets.