Chapitre 10 sur 13
Git attributes : Normaliser les fichiers
Git possède des attributs permettant de modifier le comportement par défaut de certaines opérations sur les fichiers et répertoires. Ces comportement sont spécifiés dans le fichier .gitattributes
.
Les attributs permettent par exemple de s’assurer que tous les retours à la ligne – end of line ou EOL en anglais – sont de type LF, ou permet de préciser à Git la manière d’effectuer un diff avec tel ou tel type de fichier. Dès lors, certaines opérations de check-in et check-out (switch
, checkout
, merge
, add
, switch
) sont alors altérées.
L’attribut text
Normalement, Git ne s’occupe pas du contenu des fichiers et les ajoute et les stocke tels quels. Cependant, on peut dans certains cas vouloir que Git se charge de certaines normalisations. Cela s’effectue avec l’attribut text
.
Lorsque Git opère une normalisation sur les EOL, les fichiers sont convertis et stockés à la norme Unix LF et peuvent être dynamiquement convertis pour l’espace de travail.
L’attribut text
peut être activé, désactivé ou non spécifié. Il peut en outre être spécifié pour un chemin, une extension particulière ou comme le comportement par défaut.
S’il n’est pas spécifié pour un type de fichier, Git utilise alors le comportement par défaut, s’il est désactivé, alors Git n’effectue aucune normalisation.
* text=auto
*.txt text
*.sh text eol=lf
*.vcproj text eol=crlf
*.jpg -text
Dans l’exemple précédent, on définit la normalisation pour tous les fichiers avec * text=auto
. Il faut toutefois pour cela que Git identifie le fichier comme un fichier texte et non un fichier binaire.
On spécifie ensuite des règles spécifiques à différents types de fichiers. Les fichiers .txt sont normalisés, les .sh sont normlaisés et on s’assure de plus que les nouvelles lignes soient toujours de type LF dans l’espace de travail tandis qu’elles seront toujours de type CRLF pour les fichiers .vcproj.
Enfin, les fichiers JPEG ne sont pas normalisés. Normalement Git ne les normalise pas car * text=auto
ne s’applique pas aux fichiers binaires. Cependant, la dernière ligne désactive explicitement la normalisation pour ce type de fichier.
Si lors du git status
un fichier apparaît alors qu’il ne devrait pas être normalisé, on désactive explicitement sa normalisation, et inversement avec *.ext text
pour forcer sa normalisation.
Le réglage d’EOL
L’attribut text
fonctionne, comme nous l’avons vu, par projet et par fichier. Il fonctionne de pair avec un élément de configuration : core.eol
.
core.eol
permet de définir le caractère de fin de ligne par défaut dans le répertoire de travail. Trois options s’offrent à nous : lf
, crlf
et native
. Cette dernière option, qui est celle par défaut, choisi la méthode native du système d’exploitation utilisé (LF pour Linux, macOS et BSD et CRLF pour Windows).
Cette option ne fonctionne que lorsque les fichiers sont marqués de l’attribut text
. Dans le cas contraire, rien ne se passe. Vous pouvez donc vous retrouver avec un dépôt ayant un mix de CRLF et LF. Cette probabilité est grande sur les dépôts collaboratifs car tous les développeurs n’utilisent pas le même OS.
Par ailleurs, lorsque vous copiez-collez du code depuis le web, vous copiez aussi les fins de ligne. Si les fichiers ne sont pas normalisés, vous vous retrouverez avec un mix de LF et CRLF.
Forcer la normalisation
Un dernier réglage permet de gérer la normalisation : core.autocrlf
. Celui-ci fonctionne de manière autonome et écrase core.eol
. Il fonctionne si aucun attribut text
n’est défini. En revanche, si des attributs text
sont définis, leurs directives l’emportent.
core.autocrlf
permet donc de forcer le type de retour à la ligne pour tous les fichiers. Là encore, trois options s’offrent à nous :
true
normalise tous les fichiers et les restore en CRLF dans la working area. Cette option permet de travailler avec des fichiers en CRLF tout en les commitant en LF.input
s’assure de la normalisation des fichiers avant commit et ne fait aucune conversion lors du placement dans la working. Tous les fichiers sont donc en LF à tout endroit.false
désactive cette fonctionalité, rien n’est affecté, c’est le comportement par défaut. Si vous créez des fichiers en CRLF, ils resteront aini partout, si vous avez des fichiers avec un mix de LF/CRLF, ils resteront également ainsi.
En l’absence de configuration particulière, Git ne procède donc à aucune normalisation. Les réglages core.eol
et core.autocrlf
, qu’ils soient globaux ou au niveau du projet, ne sont pas partagés avec le projet.
Les attributs permettent quant à eux de définir un comportement dans un fichier de configuration. Il sera donc partagé par tous les collaborateurs au même titre que le .gitignore
.
Considérations sur la normalisation Git
Quelque soit l’OS utilisé, tous les éditeurs de code supportent aujourd’hui aussi bien LF que CRLF. Il n’y a donc en général pas d’intérêt particulier à l’usage de core.autocrlf
. Les développeurs Windows pouvant tout à fait travailler avec du LF.
En ce qui concerne les éditeurs de code, en général :
- lors de la création d’un nouveau fichier, ils se conforment au réglage par défaut de l’OS (bien que cela puisse être changé),
- lors de l’édition d’un fichier déjà existant, ils utilitent la norme détectée dans le fichier.
- lorsque du code est copié-collé depuis une autre source, les EOL sont converties à la norme du fichier.
Il est possible de spécifier à l’éditeur de code les normes d’un projet directement via un fichier .editorconfig
. Ainsi, indépendamment des réglages du logiciel, ce fichier explicite les règles pour le projet (spaces ou tabs, LF ou CRLF…).
Normalement, en présence d’un tel fichier de config, un bon éditeur doit respecter les règles édictées dans ledit fichier. De très nombreux projets utilisent le .editorconfig
et cela permet aux éditeurs de texte d’adopter les normes du projet sans plus de configuration.
En plus de l’.editorconfig
qui est de toute façon recommandé, il est possible d’utiliser Git pour forcer la normalisation avec Git et/ou préciser des règles spécifiques pour certains types de fichiers.
En guise d’exemples, le projet V8 – le moteur JavaScript de Chrome et Node.js – force la normalisation de tous les fichiers tout en utilisant l’.editorconfig
. Quant au projet Node.js, ne sont normalisés que certains types de fichiers en en définissant l’EOL. Il utilise bien entendu aussi l’.editorconfig
pour définir ces comportements.
Si vous souhaitez utiliser les attributs Git dans votre projet, sachez qu’il existe ce dépôt GitHub qui recense de nombreux exemples pour divers types de projets.
Détecter et visualiser les EOL
Bien entendu, votre éditeur de texte vous permet très certainement de visualiser le type d’EOL d’un fichier. Il est cependant possible grâce aux outils Unix de lister tous les fichiers d’un projet qui sont dans une norme ou une autre.
On utilise pour cela les commandes find
, file
et grep
.
find . -type f -exec file {} \; | grep "CRLF" | cut -d':' -f 1
# N'oubliez pas d'exclure vos répertoires de dépendances
# Exemple en excluant les node_modules et .git
find . -path ./node_modules -prune -o -path ./.git -prune -o -type f -exec file {} \; | grep "CRLF" | cut -d':' -f 1
cat
permet de visualiser les EOL dans le fichiers, vous pourrez ainsi immédiatement voir s’ils sont mixés dans le fichier. Il faut pour cela utiliser l’option -e
. Les CRLF et LF sont respectivement matérialisés par ^M$
et $
.
cat -e functions.php
acf_add_options_page([^M$
'page_title' => 'Blocs footer',^M$
'menu_title' => 'Blocs footer',^M$
'menu_slug' => 'theme-footer-sections',^M$
'redirect' => false^M$
]);^M$
$
add_action('init', function () {$
register_nav_menus([$
'header' => 'Header menu',$
'primary' => 'Primary menu',$
'secondary' => 'Footer menu',$
'footer' => 'Footer credits menu',$
]);$
});
Enfin, pour normaliser tout un projet, on récupère la sortie de la commande précédente et on supprime simplement les CR des chaînes CRLF.
find . -path -path ./.git -prune -o -type f -exec file {} \; | grep 'CRLF' | cut -d':' -f 1 | while read -r line ; do tr -d '\r' < "$line" > "$line".tmp; rm "$line"; mv "$line".tmp "$line"; done;
Il n’est pas possible d’être exhaustif tant les attributs offrent de fonctionalités. En autres choses, ils permettent aussi de gérer les encodages incompatibles avec l’ASCII (UTF-16…) ou de personnaliser le fonctionnement des diffs.
Commentaires
Rejoignez la discussion !