web-dev-qa-db-fra.com

Quelle est la meilleure stratégie de traitement des fichiers CRLF (retour chariot, saut de ligne) avec Git?

J'ai essayé de valider des fichiers avec des lignes de fin CRLF, mais cela a échoué.

J'ai passé toute une journée de travail sur mon ordinateur Windows à essayer différentes stratégies et j'étais presque tenté de cesser d'utiliser Git et d'essayer plutôt Mercurial .

Veuillez ne partager qu’une seule bonne pratique par réponse.

578
Daniel Jomphe

Presque quatre ans après avoir posé cette question, j'ai enfin trouvé une réponse qui me satisfait complètement !

Voir les détails dans github: help Guide de Traitement des fins de ligne .

Git vous permet de définir directement les propriétés de fin de ligne pour un repo en utilisant le attribut de texte dans le fichier .gitattributes . Ce fichier est validé dans le référentiel et remplace le paramètre _core.autocrlf_, vous permettant ainsi de garantir un comportement cohérent pour tous les utilisateurs, quels que soient leurs paramètres git.

Et ainsi

L'avantage de cela est que votre configuration de fin de ligne est désormais acheminée avec votre référentiel et vous n'avez pas à vous soucier de savoir si les collaborateurs disposent des paramètres globaux appropriés.

Voici un exemple de fichier .gitattributes

_# Auto detect text files and perform LF normalization
*        text=auto

*.cs     text diff=csharp
*.Java   text diff=Java
*.html   text diff=html
*.css    text
*.js     text
*.sql    text

*.csproj text merge=union
*.sln    text merge=union eol=crlf

*.docx   diff=astextplain
*.DOCX   diff=astextplain

# absolute paths are ok, as are globs
/**/postinst* text eol=lf

# paths that don't start with / are treated relative to the .gitattributes folder
relative/path/*.txt text eol=lf
_

Il existe une pratique collection de fichiers .gitattributes prêts à l'emploi pour les langages de programmation les plus populaires. C'est utile pour commencer.

Une fois que vous avez créé ou ajusté votre .gitattributes, vous devez effectuer une opération unique une fois pour toutes fin de ligne -normalisation .

Notez que l'application GitHub Desktop peut suggérer et créer un fichier .gitattributes après avoir ouvert le dépôt Git de votre projet dans l'application. Pour essayer, cliquez sur l'icône représentant un engrenage (dans le coin supérieur droit)> Paramètres du référentiel ...> Terminaisons et attributs. Vous serez invité à ajouter le recommandé .gitattributes et si vous acceptez, l'application procédera également à une normalisation de tous les fichiers de votre référentiel. .

Enfin, l'article Attention à la fin de votre ligne fournit davantage d'informations de base et explique comment Git a évolué sur les sujets traités. Je considère que cela nécessite une lecture .

Certains membres de votre équipe utilisent probablement EGit ou JGit (des outils tels que Eclipse et TeamCity les utilisent) pour valider leurs modifications. Alors vous n'avez pas de chance, comme l'explique @gatinueta dans les commentaires de cette réponse:

Ce paramètre ne vous satisfera pas complètement si vous avez des personnes travaillant avec Egit ou JGit dans votre équipe, car ces outils ignoreront simplement .gitattributes et archiveront les fichiers CRLF sans problème https://bugs.Eclipse.org/bugs/ show_bug.cgi? id = 342372

Une astuce pourrait consister à les faire appliquer leurs modifications à un autre client, par exemple SourceTree . Notre équipe à l'époque préférait cet outil à l'Egit d'Eclipse pour de nombreux cas d'utilisation.

Qui a dit que le logiciel est facile? : - /

720
Daniel Jomphe

Ne convertissez pas les fins de ligne. Ce n’est pas à VCS d’interpréter les données, mais de les stocker et de les mettre en version. Tout éditeur de texte moderne peut lire les deux types de fin de ligne.

115
John Millikin

Vous voulez presque toujours autocrlf=input sauf si vous savez vraiment ce que vous faites.

Un contexte supplémentaire ci-dessous:

Cela devrait être soit core.autocrlf=true si vous aimez les fins de DOS, soit core.autocrlf=input si vous préférez unix-newlines. Dans les deux cas, votre référentiel Git n'aura que LF, ce qui est la bonne chose. Le seul argument de core.autocrlf=false était que l'heuristique automatique peut détecter de manière incorrecte un binaire en tant que texte et votre tuile sera alors corrompue. Ainsi, l'option core.safecrlf a été introduite pour avertir un utilisateur en cas de modification irréversible. En fait, il existe deux possibilités de modifications irréversibles: une fin de ligne mixte dans un fichier texte, cette normalisation est souhaitable. Cet avertissement peut donc être ignoré ou bien (très peu probable) que Git ait incorrectement détecté votre fichier binaire en tant que texte. Ensuite, vous devez utiliser des attributs pour indiquer à Git que ce fichier est binaire.

Le paragraphe ci-dessus a été extrait d'un fil de discussion sur gmane.org, mais il a depuis diminué.

80
Cory

Deux stratégies alternatives deviennent cohérentes concernant les fins de ligne dans des environnements mixtes (Microsoft + Linux + Mac):

A. Global par configuration de tous les référentiels

1) Convertissez tous en un seul format

find . -type f -not -path "./.git/*" -exec dos2unix {} \;
git commit -a -m 'dos2unix conversion'

2) Définissez core.autocrlf sur input sous Linux/UNIX ou true sur MS Windows (référentiel ou global)

git config --global core.autocrlf input

3) [Facultatif] définissez core.safecrlf sur true (pour arrêter) ou warn (pour chanter :) pour ajouter une protection supplémentaire en comparant si la transformation de nouvelle ligne inversée aboutit au même fichier

git config --global core.safecrlf true


B. Ou par configuration de référentiel

1) Convertissez tous en un seul format

find . -type f -not -path "./.git/*" -exec dos2unix {} \;
git commit -a -m 'dos2unix conversion'

2) ajoutez le fichier .gitattributes à votre référentiel

echo "* text=auto" > .gitattributes
git add .gitattributes
git commit -m 'adding .gitattributes for unified line-ending'

Ne vous inquiétez pas pour vos fichiers binaires - Git devrait être assez intelligent à leur sujet.


Plus d'informations sur les variables safecrlf/autocrlf

57
lukmdo

Essayez de régler l’option de configuration core.autocrlf sur true. Regardez également l'option core.safecrlf.

En fait, il semble que core.safecrlf soit peut-être déjà défini dans votre référentiel, car (c'est moi qui souligne):

Si ce n'est pas le cas pour le paramètre actuel de core.autocrlf, git rejettera le fichier.

Si tel est le cas, vous pouvez vérifier que votre éditeur de texte est configuré pour utiliser les fins de ligne de manière cohérente. Vous rencontrerez probablement des problèmes si un fichier texte contient une combinaison de fins de ligne LF et CRLF.

Enfin, j'estime que la recommandation consistant simplement à "utiliser ce que l'on vous donne" et à utiliser LF lignes terminées sous Windows causera plus de problèmes qu'elle n'en résoudra. Git a les options ci-dessus pour essayer de gérer les fins de ligne de manière judicieuse, il est donc logique de les utiliser.

10
Greg Hewgill

L'utilisation de core.autocrlf=false a arrêté la mise à jour de tous les fichiers dès que je les ai extraits dans mon projet Visual Studio 201 . Les deux autres membres de l'équipe de développement utilisent également des systèmes Windows; un environnement mixte n'a donc pas été mis en place. Cependant, les paramètres par défaut fournis avec le référentiel indiquaient toujours que tous les fichiers étaient mis à jour immédiatement après le clonage.

Je suppose que l’essentiel est de trouver le réglage CRLF qui convient à votre environnement. D'autant plus que dans de nombreux autres référentiels de nos boîtes Linux, le paramètre autocrlf = true donne de meilleurs résultats.

Plus de 20 ans plus tard, nous avons toujours affaire à des disparités de fin de ligne entre systèmes d’exploitation… triste.

9
Lance Cleveland

Ce sont les deux options pour les utilisateurs de Windows et Visual Studio qui partagent le code avec les utilisateurs de Mac ou Linux. Pour une explication détaillée, lisez le manuel de gitattributes .

* text = auto

Dans le fichier .gitattributes de votre référentiel, ajoutez:

*   text=auto

Cela normalisera tous les fichiers avec LF fins de lignes dans le référentiel.

Et selon votre système d'exploitation (paramètre core.eol), les fichiers de l'arborescence de travail seront normalisés à LF pour les systèmes Unix ou à CRLF pour les systèmes Windows.

C'est la configuration que Microsoft .NET repos utilise.

Exemple:

Hello\r\nWorld

Sera normalisé dans le repo toujours comme:

Hello\nWorld

À la caisse, l’arbre de travail dans Windows sera converti en:

Hello\r\nWorld

À la caisse, l’arbre de travail sur Mac sera laissé comme suit:

Hello\nWorld

Remarque: Si votre référentiel contient déjà des fichiers non normalisés, git status affichera ces fichiers comme étant complètement modifiés la prochaine fois que vous leur apporterez des modifications. Les autres utilisateurs auraient du mal à fusionner leurs modifications ultérieurement. Voir actualiser un référentiel après avoir changé les fins de ligne pour plus d'informations.

core.autocrlf = true

Si text n'est pas spécifié dans le fichier .gitattributes, Git utilise la variable de configuration core.autocrlf pour déterminer si le fichier doit être converti.

Pour les utilisateurs de Windows, git config --global core.autocrlf true est une excellente option pour les raisons suivantes:

  • Les fichiers sont normalisés en LF fins de lignes uniquement lorsqu'ils sont ajoutés au référentiel. S'il existe des fichiers non normalisés dans le référentiel, ce paramètre ne les touchera pas.
  • Tous les fichiers texte sont convertis en fins de ligne CRLF dans le répertoire de travail.

Le problème avec cette approche est que:

  • Si vous êtes un utilisateur Windows avec autocrlf = input, vous verrez un tas de fichiers avec des fins de ligne LF. Ce n'est pas un danger pour le reste de l'équipe, car vos commits seront toujours normalisés avec des fins de ligne LF.
  • Si vous êtes un utilisateur Windows avec core.autocrlf = false, vous verrez un groupe de fichiers avec des fins de ligne LF et vous pouvez introduire des fichiers avec des fins de ligne CRLF dans le référentiel.
  • La plupart des utilisateurs de Mac utilisent autocrlf = input et peuvent obtenir des fichiers avec les fins de fichier CRLF, probablement des utilisateurs Windows dotés de core.autocrlf = false.
7
kiewic

J'ai passé des heures à trouver le meilleur usage possible de .gitattributes, pour enfin réaliser que je ne peux pas compter dessus.
Malheureusement, tant qu'il existe des éditeurs basés sur JGit (qui ne peuvent pas gérer correctement .gitattributes), la solution sûre consiste à forcer LF partout, même au niveau de l'éditeur.

Utilisez les désinfectants anti-CRLF suivants.

--- MISE À JOUR 2 ---

Les dafaults de git client fonctionneront dans la plupart des cas. Même si vous ne possédez que des clients Windows, que des clients Linux ou les deux. Ceux-ci sont:

  • windows: core.autocrlf=true signifie convertir les lignes en CRLF à la caisse et les convertir en LF lors de l'ajout de fichiers.
  • linux: core.autocrlf=input signifie ne pas convertir les lignes à la caisse (inutile de le faire, car les fichiers doivent être validés avec LF) et convertir les lignes to LF (si nécessaire) lors de l'ajout de fichiers.

La propriété peut être définie dans différentes portées. Je suggérerais de définir explicitement la portée de --global pour éviter certains problèmes de IDE décrits à la fin.

git config core.autocrlf
git config --global core.autocrlf
git config --system core.autocrlf
git config --local core.autocrlf
git config --show-Origin core.autocrlf

Aussi, je déconseillerais fortement d’utiliser git config --global core.autocrlf false (si vous n’avez que des clients Windows) contrairement à ce qui est proposé à git documentation . La définition de false validera les fichiers avec CRLF dans le référentiel. Mais il n'y a vraiment aucune raison. Vous ne savez jamais si vous devrez partager le projet avec les utilisateurs de Linux. De plus, il s'agit d'une étape supplémentaire pour chaque client qui rejoint le projet au lieu d'utiliser les valeurs par défaut.

Maintenant, pour certains cas spéciaux de fichiers (par exemple *.bat*.sh) que vous voulez qu'ils soient extraits avec LF ou avec CRLF, vous pouvez utiliser .gitattributes

Pour résumer pour moi la meilleure pratique est la suivante:

  • Assurez-vous que tous les fichiers non binaires sont validés avec LF sur git repo (comportement par défaut).
  • Utilisez cette commande pour vous assurer qu'aucun fichier n'est commis avec CRLF: git grep -I --files-with-matches --Perl-regexp '\r' HEAD ( Remarque: sur les clients Windows ne fonctionne que via git-bash et sur les clients Linux uniquement s'ils ont été compilés avec --with-libpcre dans ./configure).
  • Si vous trouvez de tels fichiers en exécutant la commande ci-dessus, corrigez-les.
  • Utilisez uniquement le strict minimum .gitattributes
  • Demandez aux utilisateurs de définir le core.autocrlf décrit ci-dessus sur ses valeurs par défaut.
  • Ne comptez pas à 100% sur la présence de .gitattributes. Les clients git des IDE peuvent les ignorer ou les traiter différemment.

Comme dit, certaines choses peuvent être ajoutées dans les attributs de git:

# Always checkout with LF
*.sh            text eol=lf
# Always checkout with CRLF
*.bat           text eol=crlf

Je pense que d'autres options sûres pour .gitattributes au lieu d'utiliser la détection automatique pour les fichiers binaires:

  • -text (par exemple, pour les fichiers *.Zip ou *.jpg: ne seront pas traités comme du texte. Ainsi, aucune conversion de fin de ligne ne sera tentée. Des différences pourraient être possibles via les programmes de conversion)
  • text !eol (par exemple pour *.Java, *.html: traité comme du texte, mais la préférence de style eol n'est pas définie. Le paramètre client est donc utilisé.)
  • -text -diff -merge (p.ex. pour *.hugefile: non traité comme du texte. Aucune diff/fusion possible)

--- MISE À JOUR PRÉCÉDENTE ---

Exemple douloureux d'un client qui commettra des fichiers à tort:

netbeans 8.2 (sur Windows), validera à tort tous les fichiers texte avec des CRLF , sauf si vous avez explicitement défini core.autocrlf comme global . Cela contredit le comportement standard du client git et pose beaucoup de problèmes plus tard, lors de la mise à jour/fusion. C’est ce qui fait que certains fichiers paraissent différents (bien qu’ils ne le soient pas) même lorsque vous les revenez .
Le même comportement se produit dans netbeans même si vous avez ajouté le correct .gitattributes à votre projet.

L'utilisation de la commande suivante après une validation vous aidera au moins à détecter rapidement si votre référentiel git présente des problèmes de fin de ligne: git grep -I --files-with-matches --Perl-regexp '\r' HEAD

5
Marinos An

Ceci est juste une solution de contournement :

Dans des cas normaux, utilisez les solutions fournies avec git. Ceux-ci fonctionnent bien dans la plupart des cas. Forcer à LF si vous partagez le développement sur des systèmes Windows et Unix en définissant . Gitattributes .

Dans mon cas, il y avait> 10 programmeurs développant un projet sous Windows. Ce projet a été archivé avec CRLF et il n’existait pas d’option permettant de forcer à LF.

Certains paramètres ont été écrits en interne sur ma machine sans aucune influence sur le format LF; ainsi, certains fichiers ont été globalement modifiés en LF à chaque modification de fichier de petite taille.

Ma solution:

Windows-Machines: Laissez tout tel quel. Ne vous souciez de rien, puisque vous êtes un développeur Windows par défaut et que vous devez gérer comme suit: "Il n'y a pas d'autre système dans le monde entier, n'est-ce pas?"

Unix-Machines

  1. Ajoutez les lignes suivantes à la section [alias] d'une config. Cette commande répertorie tous les fichiers modifiés (c'est-à-dire modifiés/nouveaux):

    lc = "!f() { git status --porcelain \
                 | egrep -r \"^(\?| ).\*\\(.[a-zA-Z])*\" \
                 | cut -c 4- ; }; f "
    
  2. Convertissez tous les fichiers modifiés au format dos:

    unix2dos $(git lc)
    
  3. Optionnellement ...

    1. Créez un git hook pour cette action afin d'automatiser ce processus

    2. Utilisez les paramètres, incluez-les et modifiez la fonction grep pour qu'elle ne corresponde qu'à des noms de fichiers particuliers, par exemple:

      ... | egrep -r "^(\?| ).*\.(txt|conf)" | ...
      
    3. N'hésitez pas à le rendre encore plus pratique en utilisant un raccourci supplémentaire:

      c2dos = "!f() { unix2dos $(git lc) ; }; f "
      

      ... et déclenchez la conversion en tapant

      git c2dos
      
4
John Rumpel