Faire en sorte que git supprime automatiquement les espaces de fin avant de valider

220

J'utilise git avec mon équipe et je voudrais supprimer les changements d'espaces dans mes différences, journaux, fusions, etc. ) de toutes les validations telles qu'elles sont appliquées.

J'ai essayé d'ajouter ce qui suit à par ~/.gitconfigfichier, mais cela ne fait rien lorsque je valide. Peut-être qu'il est conçu pour quelque chose de différent. Quelle est la solution?

[core]
    whitespace = trailing-space,space-before-tab
[apply]
    whitespace = fix

J'utilise du rubis au cas où quelqu'un aurait des idées spécifiques au rubis. La mise en forme automatique du code avant de valider serait la prochaine étape, mais c'est un problème difficile et qui ne cause pas vraiment un gros problème.

mloughran
la source
Si la directive core.whitespace ne résout pas vos problèmes, vous pouvez également modifier le hook de pré-validation (.git / hooks / pre-commit) pour les trouver et les corriger pour vous. Voir cet article pour une description détaillée.
VolkA
2
J'ai été frustré par des erreurs d'espaces similaires et des solutions partielles similaires, et j'ai écrit un utilitaire flexible et assez complet qui peut corriger ou simplement signaler des erreurs d'espaces qui gênent les systèmes de contrôle de version: Whitespace Total Fixer sur Github (excuses si c'est trop auto-promotionnel)
Dan Lenski

Réponses:

111

Ces paramètres ( core.whitespaceet apply.whitespace) ne sont pas là pour supprimer les espaces de fin, mais pour:

  • core.whitespace: les détecter et générer des erreurs
  • apply.whitespace: et les supprimer, mais uniquement pendant le patch, pas "toujours automatiquement"

Je pense que git hook pre-commitcela ferait un meilleur travail pour cela (comprend la suppression des espaces de fin)


Notez qu'à tout moment, vous pouvez choisir de ne pas exécuter le pre-commithook:

  • temporairement: git commit --no-verify .
  • en permanence: cd .git/hooks/ ; chmod -x pre-commit

Avertissement: par défaut, un pre-commitscript (comme celui-ci ), n'a pas de fonction "supprimer la fin", mais une fonction "d'avertissement" comme:

if (/\s$/) {
    bad_line("trailing whitespace", $_);
}

Vous pourriez cependant construire un meilleur pre-commitcrochet , surtout si vous considérez que:

La validation dans Git avec seulement quelques modifications ajoutées à la zone de transfert entraîne toujours une révision «atomique» qui n'a peut - être jamais existé en tant que copie de travail et peut ne pas fonctionner .


Par exemple, Oldman propose dans une autre réponse un pre-commitcrochet qui détecte et supprime les espaces.
Étant donné que ce hook obtient le nom de fichier de chaque fichier, je recommande de faire attention à certains types de fichiers: vous ne voulez pas supprimer les espaces de fin dans les .mdfichiers (démarques)!

VonC
la source
1
Il s'avère que git peut être convaincu de corriger les espaces dans votre copie de travail via apply.whitespace, en incitant git à traiter vos modifications de copie de travail comme un patch. Voir ma réponse ci-dessous .
ntc2
> "vous ne voulez pas supprimer les espaces de fin dans les fichiers .md (markdown)" - Pourquoi cela? À quoi sert la fin des espaces blancs dans les fichiers de démarques? J'ai remarqué que certains .editorconfigfichiers ont une règle spécifique pour cela.
friederbluemle
5
@friederbluemle selon le type de démarque, un double espace de fin indique <br>: github.com/FriendsOfPHP/PHP-CS-Fixer/issues/…
VonC
La définition core.whitespacede trailing-spacewith git configne génère pas d'erreur lors de la gitvalidation dans 2.5.0.
Karl Richter
43

Vous pouvez inciter Git à réparer les espaces blancs pour vous, en incitant Git à traiter vos modifications comme un patch. Contrairement aux solutions de "crochet de pré-validation", ces solutions ajoutent des commandes de correction d'espaces à Git.

Oui, ce sont des hacks.


Solutions robustes

Les alias Git suivants sont extraits de my~/.gitconfig .

Par "robuste", je veux dire que ces alias s'exécutent sans erreur, faisant la bonne chose, que l'arborescence ou l'index soient sales. Cependant, ils ne fonctionnent pas si un interactif git rebase -iest déjà en cours; voir mon~/.gitconfig pour des vérifications supplémentaires si vous vous souciez de ce cas d'angle, où l' git add -eastuce décrite à la fin devrait fonctionner.

Si vous souhaitez les exécuter directement dans le shell, sans créer d'alias Git, copiez et collez tout entre les guillemets doubles (en supposant que votre shell ressemble à Bash).

Correction de l'index mais pas de l'arbre

L' fixwsalias Git suivant corrige toutes les erreurs d'espaces dans l'index, le cas échéant, mais ne touche pas l'arborescence:

# Logic:
#
# The 'git stash save' fails if the tree is clean (instead of
# creating an empty stash :P). So, we only 'stash' and 'pop' if
# the tree is dirty.
#
# The 'git rebase --whitespace=fix HEAD~' throws away the commit
# if it's empty, and adding '--keep-empty' prevents the whitespace
# from being fixed. So, we first check that the index is dirty.
#
# Also:
# - '(! git diff-index --quiet --cached HEAD)' is true (zero) if
#   the index is dirty
# - '(! git diff-files --quiet .)' is true if the tree is dirty
#
# The 'rebase --whitespace=fix' trick is from here:
# https://stackoverflow.com/a/19156679/470844
fixws = !"\
  if (! git diff-files --quiet .) && \
     (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git stash save FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~ && \
    git stash pop && \
    git reset --soft HEAD~ ; \
  elif (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ ; \
  fi"

L'idée est de s'exécuter git fixwsavant git commitsi vous avez des erreurs d'espaces dans l'index.

Correction de l'index et de l'arbre

L' fixws-global-tree-and-indexalias Git suivant corrige toutes les erreurs d'espaces dans l'index et l'arborescence, le cas échéant:

# The different cases are:
# - dirty tree and dirty index
# - dirty tree and clean index
# - clean tree and dirty index
#
# We have to consider separate cases because the 'git rebase
# --whitespace=fix' is not compatible with empty commits (adding
# '--keep-empty' makes Git not fix the whitespace :P).
fixws-global-tree-and-index = !"\
  if (! git diff-files --quiet .) && \
     (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git add -u :/ && \
    git commit -m FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~2 && \
    git reset HEAD~ && \
    git reset --soft HEAD~ ; \
  elif (! git diff-files --quiet .) ; then \
    git add -u :/ && \
    git commit -m FIXWS_SAVE_TREE && \
    git rebase --whitespace=fix HEAD~ && \
    git reset HEAD~ ; \
  elif (! git diff-index --quiet --cached HEAD) ; then \
    git commit -m FIXWS_SAVE_INDEX && \
    git rebase --whitespace=fix HEAD~ && \
    git reset --soft HEAD~ ; \
  fi"

Pour corriger également les espaces dans les fichiers non versionnés, procédez comme suit:

git add --intent-to-add <unversioned files> && git fixws-global-tree-and-index

Solutions simples mais pas robustes

Ces versions sont plus faciles à copier et coller, mais elles ne font pas la bonne chose si leurs conditions secondaires ne sont pas remplies.

Correction du sous-arbre enraciné dans le répertoire courant (mais réinitialise l'index s'il n'est pas vide)

Utiliser git add -epour "éditer" les patchs avec l'éditeur d'identité ::

(export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .) && git checkout . && git reset

Correction et conservation de l'index (mais échoue si l'arborescence est sale ou l'index est vide)

git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset --soft HEAD~

Correction de l'arborescence et de l'index (mais réinitialise l'index s'il n'est pas vide)

git add -u :/ && git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset HEAD~

Explication de l' export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .astuce

Avant d'apprendre l' git rebase --whitespace=fixastuce de cette réponse, j'utilisais git addpartout l'astuce la plus compliquée .

Si nous l'avons fait manuellement:

  1. Réglez apply.whitespacesur fix(vous ne devez le faire qu'une seule fois):

    git config apply.whitespace fix
    

    Cela indique à Git de corriger les espaces dans les correctifs .

  2. Convaincre Git de traiter vos modifications comme un patch :

    git add -up .
    

    Appuyez sur a+ enterpour sélectionner toutes les modifications pour chaque fichier. Vous recevrez un avertissement vous informant que Git corrige vos erreurs d'espaces.
    ( git -c color.ui=auto diffà ce stade, révèle que vos modifications non indexées sont exactement les erreurs d'espacement).

  3. Supprimez les erreurs d'espacement de votre copie de travail:

    git checkout .
    
  4. Ramenez vos modifications (si vous n'êtes pas prêt à les valider):

    git reset
    

Le GIT_EDITOR=:moyen à utiliser en :tant qu'éditeur et en tant que commande :est l'identité.

ntc2
la source
1
Je viens de le tester dans Windows: cela fonctionne très bien dans une invite de commande DOS: set VISUAL= && git add -ue . && git checkout .Notez le ' .' utilisé avec git add: c'est à cause de git1.8.3
VonC
@VonC Cela ne désactive-t-il pas définitivement VISUAL, ce qui peut par exemple entraîner une utilisation ultérieure de l' git commitutilisation du mauvais éditeur? J'enveloppe la VISUAL=partie dans un sous-shell dans ma version unix ci-dessus pour éviter cela, mais je ne sais pas si DOS a des sous-coques.
ntc2
1
Merci pour le super hack! Pour info, si vous l'avez core.editordéfini, l'exportation VISUALn'a aucun effet car le paramètre de configuration est prioritaire par man git-var. Pour remplacer cela, vous devez exporter à la GIT_EDITOR=:place.
Nick Felt
1
De plus, j'ai modifié ma version de fixwspour échouer rapidement si vous êtes déjà dans un rebase interactif car sinon il mourra git rebase --whitespace=fixet vous laissera dans un état étrange. J'ai emprunté à cette question et j'ai juste ajouté un cas supplémentaire avant le si: fixws = !"\ if test -d $(git rev-parse --git-dir)/rebase-merge ; then \ echo 'In rebase - cannot fixws' ; \ elif (! git diff-files --quiet .) && \ (! git diff-index --quiet --cached HEAD) ; then \ ...
Nick Felt
1
fyi: J'ai adapté ceci dans un hook pré-commit
Ian Kelling
29

J'ai trouvé un hook de pré-validation git qui supprime les espaces de fin .

#!/bin/sh

if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then
   against=HEAD
else
   # Initial commit: diff against an empty tree object
   against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# Find files with trailing whitespace
for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -r 's/:[0-9]+:.*//' | uniq` ; do
   # Fix them!
   sed -i 's/[[:space:]]*$//' "$FILE"
   git add "$FILE"
done
exit
cmcginty
la source
3
La deuxième sedinvocation ( sed -r 's/:[0-9]+:.*//') pourrait être remplacée par cut -f1 -d:. Cela devrait fonctionner de la même manière sur les plates-formes Linux et BSD.
Ihor Kaharlichenko
2
@IhorKaharlichenko: en fait, l'utilisation cutn'est pas aussi sûre que la seconde sed: cut échouera dans le cas (très peu probable) de noms de fichiers contenant ":". Vous pouvez utiliser awk 'NF>2{NF-=2}1'pour être en sécurité
MestreLion
1
BTW, si vous êtes sur Windows (msysgit) et utilisez core.autocrlf=true, vous voudrez peut-être ajouter dos2unix -D "$FILE"à l'intérieur de la boucle for, après sed. Sinon, il changera tous les CRLF en LF en n'émettant que sed.
jakub.g
49
Faire à l' git addintérieur d'un crochet de validation me semble assez mauvais. Que se passe-t-il si vous effectuez un transfert / validation partiel d'un fichier? Vous ne voulez pas que le dossier complet soit engagé derrière votre dos, n'est-ce pas?
Stefaan
19

Sous Mac OS (ou, probablement, n'importe quel BSD), les paramètres de la commande sed doivent être légèrement différents. Essaye ça:

#!/bin/sh

if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then
   against=HEAD
else
   # Initial commit: diff against an empty tree object
   against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

# Find files with trailing whitespace
for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | sed -E 's/:[0-9]+:.*//' | uniq` ; do
    # Fix them!
    sed -i '' -E 's/[[:space:]]*$//' "$FILE"
    git add "$FILE"
done

Enregistrez ce fichier sous .git/hooks/pre-commit- ou recherchez celui qui est déjà là, et collez le morceau inférieur quelque part à l'intérieur. Et souvenez-vous-en chmod a+xaussi.

Ou pour une utilisation globale (via les hooks de validation Git - paramètres globaux ), vous pouvez le placer $GIT_PREFIX/git-core/templates/hooks(où GIT_PREFIX est / usr ou / usr / local ou / usr / share ou / opt / local / share) et l'exécuter git initdans votre référentiel existant.

Selon git help init:

L'exécution de git init dans un référentiel existant est sûre. Il n'écrasera pas les éléments qui existent déjà. La principale raison de la réexécution de git init est de récupérer les nouveaux modèles ajoutés.

AlexChaffee
la source
7
Ce crochet ne modifie-t-il pas le fichier de travail et ne remplace-t-il pas l'index par le fichier de travail modifié? Si vous deviez 'git ajouter -p' pour construire votre index, ce hook de validation le ferait exploser.
Matthew Dutton
2
Ouais, tu as probablement raison. Quelqu'un devra peut-être réécrire ce script pour utiliser git hash-object -wet git update-index(ré) insérer le fichier munged directement dans l'index. Quelqu'un très courageux.
AlexChaffee
11

Je préfère laisser cette tâche à votre éditeur préféré.

Définissez simplement une commande pour supprimer les espaces de fin lors de l'enregistrement.

Giacomo
la source
2
Dans vim, vous pouvez le faire avec: autocmd BufWritePre .cpp, .c, *. H:% / \ s \ + $ // e
Robert Massaioli
3
Désolé, j'ai surévalué le commentaire ci-dessus avant de le tester. Il y a un "s" manquant après le signe de pourcentage, et il déplacera le curseur si un espace est trouvé, et il supprimera le dernier motif de recherche. Voir vim.wikia.com/wiki/Remove_unwanted_spaces pour de meilleures alternatives.
Seth Johnson
1
Dans emacs, c'est Mx delete-trailing-whitespace.
Mauvis Ledford
2
Mieux encore, pour emacs, définissez un crochet pour supprimer les espaces de fin avant d'enregistrer en les ajoutant (add-hook 'before-save-hook 'delete-trailing-whitespace)à votre .emacsfichier. Astuces pour les espaces blancs Emacs
Duncan Parkes
1
J'utilise (add-hook 'before-save-hook' cleanspace-cleanup) qui convertit également les tabulations en espaces.
Nils Fagerburg
10

Utilisation des attributs git et de la configuration des filtres avec git config

OK, c'est une nouvelle approche pour résoudre ce problème… Mon approche est de ne pas utiliser de hooks, mais plutôt d'utiliser des filtres et des attributs git. Ce que cela vous permet de faire, c'est de configurer, sur chaque machine sur laquelle vous développez, un ensemble de filtres qui supprimera les espaces blancs finaux supplémentaires et les lignes vierges supplémentaires à la fin des fichiers avant de les valider. Configurez ensuite un fichier .gitattributes qui indique à quels types de fichiers le filtre doit être appliqué. Les filtres ont deux phases, cleanqui sont appliquées lors de l'ajout de fichiers à l'index, etsmudge qui sont appliquées lors de leur ajout au répertoire de travail.

Dites à votre git de rechercher un fichier d'attributs global

Tout d'abord, dites à votre configuration globale d'utiliser un fichier d'attributs global:

git config --global core.attributesfile ~/.gitattributes_global

Créer des filtres globaux

Maintenant, créez le filtre:

git config --global filter.fix-eol-eof.clean fixup-eol-eof %f
git config --global filter.fix-eol-eof.smudge cat
git config --global filter.fix-eol-eof.required true

Ajoutez la magie des scripts sed

Enfin, mettez le fixup-eol-eof script quelque part sur votre chemin et rendez-le exécutable. Le script utilise sed pour effectuer certaines modifications à la volée (supprimer les espaces et les blancs à la fin des lignes et les lignes blanches superflues à la fin du fichier)

fixup-eol-eof devrait ressembler à ceci:

#!/bin/bash
sed -e 's/[  ]*$//' -e :a -e '/^\n*$/{$d;N;ba' -e '}' $1

mon essentiel de cela

Dites à git à quels types de fichiers appliquer votre filtre nouvellement créé

Enfin, créez ou ouvrez ~ / .gitattributes_global dans votre éditeur préféré et ajoutez des lignes comme:

pattern attr1 [attr2 [attr3 […]]]

Donc, si nous voulons résoudre le problème des espaces, pour tous nos fichiers source c, nous ajouterions une ligne qui ressemble à ceci:

*.c filter=fix-eol-eof

Discussion du filtre

Le filtre a deux phases, la phase de nettoyage qui est appliquée lorsque des éléments sont ajoutés à l'index ou archivés, et la phase de maculage lorsque git place des éléments dans votre répertoire de travail. Ici, notre tache exécute simplement le contenu via la catcommande qui devrait les laisser inchangés, à l'exception peut-être d'ajouter un caractère de fin de ligne s'il n'y en avait pas à la fin du fichier. La commande clean est le filtrage des espaces que j'ai bricolé à partir de notes sur http://sed.sourceforge.net/sed1line.txt . Il semble qu'il doit être mis dans un script shell, je n'ai pas pu comprendre comment injecter la commande sed, y compris l'assainissement des lignes supplémentaires superflues à la fin du fichier directement dans le fichier git-config. (Vous POUVEZse débarrasser des blancs de fin, cependant, sans avoir besoin d'un script sed séparé, il suffit de définir filter.fix-eol-eofquelque chose comme sed 's/[ \t]*$//' %foù se \ttrouve un onglet réel, en appuyant sur tab.)

L'exigence require = true déclenche une erreur en cas de problème, afin de vous éviter des ennuis.

Veuillez me pardonner si ma langue concernant git est imprécise. Je pense avoir une assez bonne compréhension des concepts mais j'apprends encore la terminologie.

zbeekman
la source
Approche intéressante. +1
VonC
Merci @VonC! Je veux également saisir cette occasion pour souligner que les attributs git peuvent être configurés de manière per-repisitory dans le .gitdossier plutôt que globalement, ce qui pourrait être plus logique.
zbeekman
9

J'ai écrit ce crochet de pré-validation, qui supprime uniquement l'espace blanc de fin des lignes que vous avez modifiées / ajoutées, car les suggestions précédentes ont tendance à créer des validations illisibles si les fichiers cibles ont trop d'espace blanc de fin.

#!/bin/sh

if git rev-parse --verify HEAD >/dev/null 2>&1 ; then
   against=HEAD
else
   # Initial commit: diff against an empty tree object
   against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

IFS='
'

files=$(git diff-index --check --cached $against -- | sed '/^[+-]/d' | perl -pe 's/:[0-9]+:.*//' | uniq)
for file in $files ; do
    diff=$(git diff --cached $file)
    if test "$(git config diff.noprefix)" = "true"; then
        prefix=0
    else
        prefix=1
    fi
    echo "$diff" | patch -R -p$prefix
    diff=$(echo "$diff" | perl -pe 's/[ \t]+$// if m{^\+}')
    out=$(echo "$diff" | patch -p$prefix -f -s -t -o -)
    if [ $? -eq 0 ]; then
        echo "$diff" | patch -p$prefix -f -t -s
    fi
    git add $file
done
urandom
la source
1
Intéressant. +1. Voir mon autre réponse pour calculer l'arbre vide.
VonC
1
Bonne idée, c'est exactement ce que je voudrais. Cependant, soyez prudent lorsque vous l'utilisez! Pour moi, sur OSX et git version 2.3.5, il supprime tout changement ajouté mais non engagé que j'ai mis en scène. Je serais toujours intéressé par une solution de travail pour cela.
Casper
9

Veuillez essayer mes crochets de pré-validation , il peut détecter automatiquement les espaces de fin et les supprimer . Je vous remercie!

ça peut marcher sous GitBash(windows), Mac OS X and Linux!


Instantané:

$ git commit -am "test"
auto remove trailing whitespace in foobar/main.m!
auto remove trailing whitespace in foobar/AppDelegate.m!
[master 80c11fe] test
1 file changed, 2 insertions(+), 2 deletions(-)
vieil homme
la source
1
Intéressant. +1. J'ai référencé votre crochet dans ma propre réponse
VonC
@VonC Merci pour votre affirmation! Pour le '.md', je n'ai trouvé que git commit -no-verifydes sugesstions?
oldman
Je préfère rendre le crochet capable de détecter le .mdfichier et non de supprimer les espaces blancs, plutôt que de demander à l'utilisateur final d'ajouter une --no-verifyoption sur le git commit.
VonC
Échoue si la validation d'un fichier / répertoire commençant par un +ou-
Rody Oldenhuis
6

Voici une version compatible ubuntu + mac os x:

#!/bin/sh
#

# A git hook script to find and fix trailing whitespace
# in your commits. Bypass it with the --no-verify option
# to git-commit
#

if git-rev-parse --verify HEAD >/dev/null 2>&1 ; then
  against=HEAD
else
  # Initial commit: diff against an empty tree object
  against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi
# Find files with trailing whitespace
for FILE in `exec git diff-index --check --cached $against -- | sed '/^[+-]/d' | (sed -r 's/:[0-9]+:.*//' > /dev/null 2>&1 || sed -E 's/:[0-9]+:.*//') | uniq` ; do
  # Fix them!
  (sed -i 's/[[:space:]]*$//' "$FILE" > /dev/null 2>&1 || sed -i '' -E 's/[[:space:]]*$//' "$FILE")
  git add "$FILE"
done

# Now we can commit
exit

S'amuser

sdepold
la source
On dirait que la seule différence entre la vôtre et la mienne est que vous vérifiez que sed remplacera réellement quelque chose avant de réécrire le fichier ... Je ne suis pas sûr que ce soit important car git ne valide pas les changements qui ne changent en fait rien. Je suppose que c'est légèrement plus sûr, mais aussi légèrement plus lent, et je préfère la clarté de ne pas répéter les regex deux fois sur une même ligne. De gustibus non disputandum est!
AlexChaffee
non la différence est que la version utilise d'abord la syntaxe ubuntu et (si cela échoue) ensuite celle osx.
sdepold
1
J'ai édité le message de sdepold, il devrait pouvoir également autoriser les espaces blancs dans les noms de fichiers maintenant.
imme
5

J'y pensais aujourd'hui. C'est tout ce que j'ai fini par faire pour un projet java:

egrep -rl ' $' --include *.java *  | xargs sed -i 's/\s\+$//g'
Grant Murphy
la source
3

Pour les utilisateurs de Sublime Text .

Définissez correctement les paramètres suivants dans la configuration des paramètres utilisateur .

"trim_trailing_white_space_on_save": true

Haris Krajina
la source
1
Est-ce un moyen de définir cela par type de fichier? J'ai des *.mdfichiers (markdown) qui s'appuient sur "" (espaces doubles finaux) pour marquer un simple <br />, et ce paramètre semble s'appliquer à tous les fichiers, y compris ceux dont je ne veux pas supprimer les espaces finaux.
VonC
@VonC Il existe une hiérarchie sur la façon dont la configuration est appliquée plus de détails ici, stackoverflow.com/questions/16983328/… j'espère que cela aide
Haris Krajina
2

la boucle for pour les fichiers utilise la variable shell $ IFS. dans le script donné, les noms de fichiers contenant un caractère qui se trouve également dans la variable $ IFS seront considérés comme deux fichiers différents dans la boucle for. Ce script le corrige: le modificateur de mode multiligne tel que sed-manual ne semble pas fonctionner par défaut sur ma boîte Ubuntu, j'ai donc cherché une implémentation différente et l'ai trouvé avec une étiquette itérative, essentiellement il ne commencera la substitution que sur le dernière ligne du fichier si je l'ai bien compris.

#!/bin/sh
#

# A git hook script to find and fix trailing whitespace
# in your commits. Bypass it with the --no-verify option
# to git-commit
#

if git rev-parse --verify HEAD >/dev/null 2>&1
then
    against=HEAD
else
    # Initial commit: diff against an empty tree object
    against=4b825dc642cb6eb9a060e54bf8d69288fbee4904
fi

SAVEIFS="$IFS"
# only use new-line character as seperator, introduces EOL-bug?
IFS='
'
# Find files with trailing whitespace
for FILE in $(
    git diff-index --check --cached $against -- \
    | sed '/^[+-]/d' \
    | ( sed -r 's/:[0-9]+:.*//' || sed -E 's/:[0-9]+:.*//' ) \
    | uniq \
)
do
# replace whitespace-characters with nothing
# if first execution of sed-command fails, try second one( MacOSx-version)
    (
        sed -i ':a;N;$!ba;s/\n\+$//' "$FILE" > /dev/null 2>&1 \
        || \
        sed -i '' -E ':a;N;$!ba;s/\n\+$//' "$FILE" \
    ) \
    && \
# (re-)add files that have been altered to git commit-tree
#   when change was a [:space:]-character @EOL|EOF git-history becomes weird...
    git add "$FILE"
done
# restore $IFS
IFS="$SAVEIFS"

# exit script with the exit-code of git's check for whitespace-characters
exec git diff-index --check --cached $against --

[1] Modèle sed-subsition: comment remplacer une nouvelle ligne (\ n) en utilisant sed? .

immeëmosol
la source
2

Cela ne supprime pas automatiquement les espaces avant un commit, mais il est assez facile à effectuer. J'ai mis le script perl suivant dans un fichier nommé git-wsf (git whitespace fix) dans un répertoire dans $ PATH pour que je puisse:

git wsf | sh

et il supprime tous les espaces uniquement des lignes de fichiers qui git les rapports en tant que diff.

#! /bin/sh
git diff --check | perl -x $0
exit

#! /usr/bin/perl

use strict;

my %stuff;
while (<>) {
    if (/trailing whitespace./) {
        my ($file,$line) = split(/:/);
        push @{$stuff{$file}},$line;
    }
}

while (my ($file, $line) = each %stuff) {
    printf "ex %s <<EOT\n", $file;
    for (@$line) {
        printf '%ds/ *$//'."\n", $_;
    }
    print "wq\nEOT\n";
}
davidc
la source
0

Un peu tard, mais comme cela pourrait aider quelqu'un là-bas, c'est parti.

Ouvrez le fichier dans VIM. Pour remplacer les onglets par des espaces, tapez ce qui suit dans la ligne de commande vim

:%s#\t#    #gc

Pour se débarrasser des autres espaces vides de fin

:%s#\s##gc

C'est à peu près tout pour moi. C'est fastidieux si vous avez beaucoup de fichiers à éditer. Mais je l'ai trouvé plus facile que les hooks de pré-validation et le travail avec plusieurs éditeurs.

hriddle
la source
Si cela devient fastidieux - et si vous avez une sauvegarde de ce que vous êtes sur le point d'éditer - alors j'utilise souvent sed pour changer les tabulations en espaces: sed -i 's|\t| |g' filenames(espaces en position de remplacement). Notez que vous pouvez utiliser find pour obtenir vos noms de fichiers. Si vous n'avez pas réfléchi à la façon d'obtenir cette sauvegarde, je valide généralement tout, puis «annule» la validation avec une réinitialisation logicielle à l'endroit où je suis; parfois j'ajoute tout à l'arborescence mais je ne m'engage pas, et parfois j'utilise le stash / apply (pas pop!). Si je me sens anxieux, je synchronise tout mon arbre vers un endroit sûr avant de me mêler ...
sage
0

Pour supprimer les espaces blancs de fin à la fin de la ligne d'un fichier de manière portable, utilisez ed:

test -s file &&
   printf '%s\n' H ',g/[[:space:]]*$/s///' 'wq' | ed -s file
nat
la source
-1

Cela ne résoudra probablement pas directement votre problème, mais vous voudrez peut-être les définir via git-config dans votre espace de projet réel, qui édite ./.git/config par opposition à ~ / .gitconfig. Agréable de garder les paramètres cohérents entre tous les membres du projet.

git config core.whitespace "trailing-space,space-before-tab"
git config apply.whitespace "trailing-space,space-before-tab"
bojo
la source
3
afaik, les paramètres dans .git ne sont partagés avec personne d'autre; ils sont spécifiques à votre
dépôt