web-dev-qa-db-fra.com

Essayer de réparer les fins de ligne avec git filter-branch, mais sans succès

J'ai été piqué par le problème de fin de ligne de Windows/Linux avec git. Il semble, via GitHub, MSysGit et d’autres sources, que la meilleure solution consiste à configurer votre dépôt local pour qu’il utilise des fins de ligne de style linux, mais définissez core.autocrlf à true. Malheureusement, je ne l'ai pas fait assez tôt, alors chaque fois que je modifie, les fins de ligne sont bouchées.

Je pensais avoir trouvé une réponse ici mais je ne peux pas la faire fonctionner pour moi. Ma connaissance de la ligne de commande Linux est limitée au mieux, donc je ne suis même pas sûr de ce que la ligne "xargs fromdos" fait dans son script. Je continue à recevoir des messages indiquant qu'il n'existe aucun fichier ou répertoire de ce type, et lorsque je parviens à le diriger vers un répertoire existant, il me dit que je ne dispose pas d'autorisations.

J'ai essayé cela avec MSysGit sous Windows et via le terminal Mac OS X.

266
Brian Donahue

La documentation git pour gitattributes documente maintenant une autre approche pour "corriger" ou normaliser toutes les fins de ligne de votre projet. En voici l'essentiel:

$ echo "* text=auto" >.gitattributes
$ git add --renormalize .
$ git status        # Show files that will be normalized
$ git commit -m "Introduce end-of-line normalization"

Si des fichiers qui ne doivent pas être normalisés apparaissent dans l'état git, désactivez leur attribut text avant d'exécuter git add -u.

manual.pdf -text

Inversement, la normalisation peut être activée manuellement dans les fichiers texte que git ne détecte pas.

weirdchars.txt text

Ceci tire parti d'un nouveau --renormalize flag ajouté dans git v2.16.0, publié en janvier 2018. Pour les anciennes versions de git, quelques étapes supplémentaires sont nécessaires:

$ echo "* text=auto" >>.gitattributes
$ rm .git/index     # Remove the index to force git to
$ git reset         # re-scan the working directory
$ git status        # Show files that will be normalized
$ git add -u
$ git add .gitattributes
$ git commit -m "Introduce end-of-line normalization"
184
Russ Egan

Le moyen le plus simple de résoudre ce problème consiste à créer un commit qui corrige toutes les fins de ligne. En supposant que vous n’ayez aucun fichier modifié, procédez comme suit.

# From the root of your repository remove everything from the index
git rm --cached -r .

# Change the autocrlf setting of the repository (you may want 
#  to use true on windows):
git config core.autocrlf input

# Re-add all the deleted files to the index
# (You should get lots of messages like:
#   warning: CRLF will be replaced by LF in <file>.)
git diff --cached --name-only -z | xargs -0 git add

# Commit
git commit -m "Fixed crlf issue"

# If you're doing this on a Unix/Mac OSX clone then optionally remove
# the working tree and re-check everything out with the correct line endings.
git ls-files -z | xargs -0 rm
git checkout .
385
CB Bailey

Ma procédure pour traiter les fins de ligne est la suivante (test de combat sur de nombreux dépôts):

Lors de la création d'un nouveau dépôt:

  • mettre .gitattributes dans le tout premier commit avec d’autres fichiers typiques comme .gitignore et README.md

Lorsqu'il s'agit d'un dépôt existant:

  • Créer/modifier .gitattributes en conséquence
  • git commit -a -m "Modified gitattributes"
  • git rm --cached -r . && git reset --hard && git commit -a -m 'Normalize CRLF' -n"
    • -n (--no-verify est de sauter les hooks de pré-commit)
    • Je dois le faire assez souvent pour le définir comme un alias alias fixCRLF="..."
  • répéter la commande précédente
    • oui, c'est voodoo, mais en général je dois exécuter la commande deux fois, la première fois qu'il normalise certains fichiers, la deuxième fois encore plus de fichiers. Généralement, il est probablement préférable de répéter jusqu'à ce qu'aucun nouveau commit ne soit créé :)
  • faire des allers-retours entre l'ancienne (juste avant la normalisation) et la nouvelle branche à quelques reprises. Après avoir changé de branche, parfois, git trouvera encore plus de fichiers à renormaliser!

Dans .gitattributes Je déclare explicitement que tous les fichiers texte ont LF EOL ), car les outils Windows sont généralement compatibles avec LF tant que les Les outils Windows ne sont pas compatibles avec CRLF (même de nombreux outils de ligne de commande nodejs supposent LF et peuvent donc modifier l’EOL dans vos fichiers).

Contenu de .gitattributes

Ma .gitattributes ressemble habituellement à:

*.html eol=lf
*.js   eol=lf
*.json eol=lf
*.less eol=lf
*.md   eol=lf
*.svg  eol=lf
*.xml  eol=lf

Pour savoir quelles extensions distinctes sont suivies par git dans le référentiel actuel, regardez ici

Problèmes après la normalisation

Une fois que cela est fait, il y a une autre mise en garde commune.

Supposons que votre master soit déjà à jour et normalisé, puis que vous passiez à la caisse outdated-branch. Bien souvent, juste après avoir vérifié cette branche, git marque de nombreux fichiers comme modifiés.

La solution consiste à faire un faux commit (git add -A . && git commit -m 'fake commit') puis git rebase master. Après le rebase, le faux commit devrait disparaître.

11
jakub.g

Voici comment j'ai corrigé toutes les fins de ligne de l'historique en utilisant git filter-branch. Le ^M le caractère doit être entré avec CTRL-V + CTRL-M. J'ai utilisé dos2unix pour convertir les fichiers car cela ignore automatiquement les fichiers binaires.

$ git filter-branch --tree-filter 'grep -IUrl "^M" | xargs -I {} dos2unix "{}"'
4
pfrenssen
git status --short|grep "^ *M"|awk '{print $2}'|xargs fromdos

Explication:

  • git status --short

    Ceci affiche chaque ligne dont git est et n’est pas au courant. Les fichiers qui ne sont pas sous le contrôle de git sont marqués au début de la ligne avec un '?'. Les fichiers modifiés sont marqués d'un M.

  • grep "^ *M"

    Ceci filtre uniquement les fichiers qui ont été modifiés.

  • awk '{print $2}'

    Cela montre seulement le nom de fichier sans aucun marqueur.

  • xargs fromdos

    Cela prend les noms de fichiers de la commande précédente et les exécute via l'utilitaire 'fromdos' pour convertir les fins de ligne.

4
Lloyd Moore

Le "| xargs fromdos" lit à partir de l'entrée standard (les fichiers find trouve) et l'utilise comme argument de la commande fromdos, qui convertit les fins de ligne. (Est-ce que fromdos est standard dans ces environnements? Je suis habitué à dos2unix). Notez que vous pouvez éviter d'utiliser xargs (particulièrement utile si vous avez suffisamment de fichiers pour que la liste d'arguments soit trop longue pour xargs):

find <path, tests...> -exec fromdos '{}' \;

ou

find <path, tests...> | while read file; do fromdos $file; done

Je ne suis pas totalement sûr de vos messages d'erreur. J'ai testé cette méthode avec succès. Quel programme produit chaque? Pour quels fichiers/répertoires n'avez-vous pas les autorisations? Cependant, voici un essai pour deviner ce que cela pourrait être:

Un moyen simple d'obtenir une erreur "fichier non trouvé" pour le script est d'utiliser un chemin relatif - utilisez un chemin absolu. De même, vous pouvez obtenir une erreur d'autorisation si vous n'avez pas rendu votre script exécutable (chmod + x).

Ajoutez des commentaires et je vais essayer de vous aider!

3
Cascabel

ok ... sous cygwin, fromdos n'est pas facilement disponible, et awk substeb vous explose au visage si vous avez des espaces dans les chemins d'accès aux fichiers modifiés (ce que nous avions), j'ai donc dû le faire un peu différemment:

git status --short | grep "^ *M" | sed 's/^ *M//' | xargs -n 1 dos2unix

bravo à @lloyd pour le gros de cette solution

1
Anton K