Faire git supprimer automatiquement les espaces vides avant de les utiliser

j'utilise git avec mon équipe et je voudrais supprimer les changements d'espace de mes diffs, logs, merges, etc. Je suppose que la façon la plus simple de faire cela serait que git supprime automatiquement les blancs espace de fuite (et autres erreurs d'espace) de toutes les propagations au fur et à mesure qu'elles sont appliquées.

j'ai essayé d'ajouter ce qui suit au fichier ~/.gitconfig mais cela ne fait rien quand je commets. 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 ruby au cas où quelqu'un aurait des idées spécifiques à ruby. Le formatage automatique du code avant de le commettre serait la prochaine étape, mais c'est un problème difficile et ne pas vraiment causer un gros problème.

201
demandé sur mloughran 2009-02-26 21:52:20

16 réponses

ces paramètres ( core.whitespace et apply.whitespace ) ne sont pas là pour supprimer les espaces de fuite mais pour:

  • core.whitespace : détectez-les et augmentez les erreurs
  • apply.whitespace : et les enlever, mais seulement pendant le patch, pas "toujours automatiquement"

je crois que le git hook pre-commit serait faire un meilleur travail pour cela (y compris l'élimination des espaces)


notez qu'à tout moment vous pouvez choisir de ne pas exécuter le pre-commit crochet:

  • Temporairement: git commit --no-verify .
  • de façon permanente: cd .git/hooks/ ; chmod -x pre-commit

Attention: par défaut, un pre-commit script "(comme celui-ci ), a pas un "supprimer de fuite" fonctionnalité", mais un "avertissement" fonctionnalité comme:

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

vous pourriez cependant construire une meilleure pre-commit crochet , surtout si vous considérez que:

s'engager dans Git, avec seulement quelques changements par rapport à la zone de transit toujours conduit à une "atomique" révision peut n'avoir jamais existé comme une copie de travail et ne peuvent pas travailler .


Par exemple, oldman propose dans une autre réponse un pre-commit crochet qui permet de détecter et de supprimer l'espace.

Depuis que ce crochet obtenir le nom de fichier de chaque fichier, je recommande d'être prudent pour certains types de fichiers: vous ne voulez pas supprimer les blancs arrière-plan dans .md (markdown) fichiers!

100
répondu VonC 2017-09-08 16:57:55

vous pouvez tromper Git dans la fixation de l'espace blanc pour vous, en trompant git dans le traitement de vos changements comme un patch. Contrairement aux solutions" pre-commit hook", ces solutions ajoutent des commandes de fixation d'espaces à Git.

Oui, ce sont des piratages.


solutions Robustes

les alias Git suivants sont tirés de mon ~/.gitconfig .

Par "robuste" je veux dire que ces alias fonctionnent sans erreur, faisant la bonne chose, peu importe si l'arbre ou de l'index sont sales. Cependant, ils ne fonctionnent pas si un git rebase -i interactif est déjà en cours; voir mon ~/.gitconfig pour des vérifications supplémentaires si vous vous souciez de cette affaire de coin, où le tour git add -e décrit à la fin devrait fonctionner.

si vous voulez les exécuter directement dans le shell, sans créer de Git alias, juste copiez et collez tout entre les guillemets (en supposant que votre coquille est Bash comme).

fixer l'index mais pas l'arbre

la suivante fixws git alias corrige toutes les erreurs d'espace dans l'index, s'il y en a, mais ne touche pas à l'arbre:

# 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 lancer git fixws avant git commit si vous avez erreurs d'espace dans l'index.

fixer l'index et l'arbre

Le suivant fixws-global-tree-and-index Git alias résout tous les espaces erreurs dans l'index et l'arbre, s'il y a lieu:

# 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 fixer aussi les espaces dans les fichiers non suivis en versions, faites

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

solutions simples mais non robustes

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

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

utilisant git add -e pour "éditer" les patches avec l'éditeur d'identité : :

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

Fixer et préserver l'index (mais échoue si l'arbre est sale ou si l'indice est vide)

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

Fixer l'arbre 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 du export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue . trick

avant que j'ai appris sur le git rebase --whitespace=fix astuce de cette réponse j'ai utilisé le plus compliqué git add astuce partout.

si nous le faisions manuellement:

  1. Set apply.whitespace à fix (vous n'avez qu'à le faire une seule fois):

    git config apply.whitespace fix
    

    ce qui indique à Git fixez whitespace dans patches .

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

    git add -up .
    

    Hit un + entrée pour sélectionner tous les changements pour chaque fichier. Vous recevrez un avertissement à propos de Git corrigeant vos erreurs whitespace.

    ( git -c color.ui=auto diff à ce point révèle que vos changements non-indexés sont exactement l'espace des erreurs).

  3. supprimez les erreurs d'espace de votre copie de travail:

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

    git reset
    

le GIT_EDITOR=: signifie utiliser : comme éditeur, et comme commande : est l'identité.

41
répondu ntc2 2017-05-23 12:34:53

j'ai trouvé un git pre-commit hook qui supprime fin d'espaces .

#!/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
29
répondu cmcginty 2017-04-14 05:01:52

sur Mac OS (ou, probablement, tout BSD), Les paramètres de la commande sed doivent être légèrement différents. Essayez ceci:

#!/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

sauvegarder ce fichier comme .git/hooks/pre-commit -- ou chercher celui qui est déjà là, et coller le morceau inférieur quelque part à l'intérieur. Et rappelez-vous de chmod a+x lui aussi.

ou pour une utilisation globale (via git commit hooks-global settings ) vous pouvez le mettre dans $GIT_PREFIX/git-core/templates/hooks (où GIT_PREFIX est /usr ou /usr /local ou/usr /share ou/opt/local / share) et lancez git init dans vos repos existants.

selon git help init :

exécuter git init dans un dépôt existant est sans danger. Cela n'écrasera pas les choses qui sont déjà là. La principale raison pour laquelle vous relancez git init est de récupérer des modèles nouvellement ajoutés.

19
répondu AlexChaffee 2017-05-23 11:55:01

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

il suffit de définir une commande pour supprimer les espaces de fuite lors de la sauvegarde.

10
répondu Giacomo 2009-02-26 21:34:44

j'ai écrit ce crochet pre-commit, qui ne supprime que l'espace blanc traînant des lignes que vous avez modifiées/ajoutées, puisque les suggestions précédentes ont tendance à créer des propagations illisibles si les fichiers cibles ont trop d'espace blanc traînant.

#!/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
9
répondu urandom 2013-10-14 07:33:56

essayez mon pré-validation crochets , il peut détecter automatiquement de fuite-les espaces et les supprimer . Je vous remercie!

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


Snapshot:

$ 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(-)
8
répondu oldman 2014-03-28 04:44:37

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

Avoir du plaisir

6
répondu sdepold 2011-06-07 09:09:03

utilisant les attributs git, et filtres configuration avec la configuration git

OK, c'est une nouvelle façon de résoudre ce problème... mon approche est de ne pas utiliser de crochets, 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 supprimeront un espace blanc arrière supplémentaire et des lignes vierges supplémentaires à la fin des fichiers avant de les propager. Puis l'installation d'un .gitattributes fichier qui indique quels types de fichiers le filtre doit être appliqué. Les filtres ont deux phases, clean qui est appliqué lors de l'ajout de fichiers à l'index, et smudge qui est appliqué lors de l'ajout de fichiers au répertoire de travail.

dites à votre git de chercher 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éer 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

Ajouter le script sed magie

enfin, mettez le script fixup-eol-eof quelque part sur votre chemin, et rendez-le exécutable. Le script utilise sed pour en faire à la volée (supprimer les espaces et les blancs à la fin des lignes, et les lignes vides étrangères à la fin du fichier)

fixup-eol-expressions du folklore devrait ressembler à ceci:

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

mon essentiel de ce

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

enfin, créer ou ouvrir~/.gitattributes_global dans votre éditeur préféré et ajoutez des lignes comme:

pattern attr1 [attr2 [attr3 […]]]

donc si nous voulons corriger la question des espaces, pour tous nos fichiers c source, nous ajouterions une ligne qui ressemble à ceci:

*.c filter=fix-eol-eof

Discussion du filtre

le filtre a deux phases, la phase propre qui est appliquée quand les choses sont ajoutées à l'index ou enregistrées, et la phase smudge lorsque git met des choses dans votre répertoire de travail. Ici, notre smudge ne fait que passer le contenu à travers la commande cat qui devrait les laisser inchangés, à l'exception de l'ajout possible d'un caractère de nouvelle ligne s'il n'y en avait pas un à la fin du fichier. La commande clean est le filtrage des espaces blancs que j'ai concocté à partir de notes à http://sed.sourceforge.net/sed1line.txt . Il il semble que cela doive être mis dans un script shell, Je n'ai pas pu trouver comment injecter la commande sed, y compris l'assainissement des lignes supplémentaires étrangères à la fin du fichier directement dans le fichier git-config. (Vous PEUT se débarrasser des espaces vides de fin, cependant, sans la nécessité d'un autre script sed, il suffit de régler le filter.fix-eol-eof à quelque chose comme sed 's/[ \t]*$//' %f où le \t est un onglet en appuyant sur tab.)

Le besoin = true provoque une erreur d'être soulevé si quelque chose va mal, pour vous garder hors des problèmes.

s'il vous plaît pardonnez-moi si mon langage concernant git est imprécis. Je pense que j'ai une assez bonne compréhension des concepts, mais je suis encore en train d'apprendre la terminologie.

6
répondu zbeekman 2015-02-11 04:07:35

y pensait 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'
5
répondu Grant Murphy 2012-09-20 07:54:14

la boucle for-pour les fichiers utilise la variable $IFS shell. dans le script donné, les noms de fichiers avec un caractère qui se trouve aussi dans la variable $IFS seront considérés comme deux fichiers différents dans la boucle for. Ce script corrige: le modificateur de mode multiligne comme donné sed-manuel ne semble pas fonctionner par défaut sur ma boîte ubuntu, donc j'ai cherché une implémentation différente et j'ai trouvé ceci avec une étiquette itérative, essentiellement il ne commencera la substitution sur la dernière ligne du fichier que si j'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] sed-subsubtion pattern: Comment puis-je remplacer une nouvelle ligne (\n) en utilisant sed? .

2
répondu immeëmosol 2017-05-23 12:26:36

Pour Sublime Text des utilisateurs.

suivi correctement en vous Configuration-utilisateur configuration.

"trim_trailing_white_space_on_save": true

2
répondu Haris Krajina 2014-06-19 13:37:50

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

git fsm | sh

et il supprime tous les espaces seulement des lignes de fichiers que git déclare comme diff.

#! /bin/sh
git diff --check | perl -x "151900920"
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";
}
1
répondu davidc 2017-10-21 03:10:35

un peu en retard mais puisque cela pourrait aider quelqu'un là-bas, voilà.

ouvrir 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 blancs traînants

:%s#\s##gc

Ce joli beaucoup fait pour moi. C'est fastidieux si vous avez beaucoup de fichiers à modifier. Mais j'ai trouvé ça plus facile que des hooks de pré-propagation et de travailler avec plusieurs éditeurs.

0
répondu hriddle 2014-07-25 22:20:53

pour supprimer l'espace de fin de ligne dans un fichier, utilisez ed :

test -s file &&
   printf '%s\n' H ',g/[[:space:]]*$/s///' 'wq' | ed -s file
0
répondu nat 2014-12-02 13:50:00

cela ne résoudra probablement pas directement votre problème, mais vous voudrez peut-être mettre ceux-ci 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érente entre tous les membres du projet.

git config core.whitespace "trailing-space,space-before-tab"
git config apply.whitespace "trailing-space,space-before-tab"
-1
répondu bojo 2009-02-26 19:12:18