Chapitre 10 sur 13

Git attributes : Normaliser les fichiers

Laisser un commentaire

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 :

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 :

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 !

Vous pouvez utiliser Markdown pour les liens [ancre de lien](url), la mise en *italique* et en **gras**. Enfin pour le code, vous pouvez utiliser la syntaxe `inline` et la syntaxe bloc

```
ceci est un bloc
de code
```