Lassen Sie git vor dem Festschreiben automatisch nachgestellte Leerzeichen entfernen


220

Ich verwende git mit meinem Team und möchte Leerzeichenänderungen aus meinen Diffs, Protokollen, Zusammenführungen usw. entfernen. Ich gehe davon aus, dass der einfachste Weg, dies zu tun, darin besteht, dass git nachfolgendes Leerzeichen (und andere Leerzeichenfehler) automatisch entfernt ) von allen Commits, wie sie angewendet werden.

Ich habe versucht, Folgendes per ~/.gitconfigDatei hinzuzufügen, aber es macht nichts, wenn ich festschreibe. Vielleicht ist es für etwas anderes konzipiert. Was ist die Lösung?

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

Ich benutze Ruby, falls jemand irgendwelche rubinspezifischen Ideen hat. Die automatische Code-Formatierung vor dem Festschreiben wäre der nächste Schritt, aber das ist ein schwieriges Problem und verursacht nicht wirklich ein großes Problem.


Wenn die Anweisung core.whitespace Ihre Probleme nicht behebt, können Sie auch den Pre-Commit-Hook (.git / hooks / pre-commit) ändern, um sie für Sie zu finden und zu beheben. In diesem Beitrag finden Sie eine detaillierte Beschreibung.
VolkA

2
Ich war frustriert über ähnliche Whitespace-Fehler und Teillösungen und schrieb ein flexibles und ziemlich funktionsreiches Dienstprogramm, mit dem Whitespace-Fehler behoben oder einfach gemeldet werden können, die Versionskontrollsysteme stören: Whitespace Total Fixer auf Github (Entschuldigung, wenn dies zu selbstbewusst ist)
Dan Lenski

Antworten:


111

Diese Einstellungen ( core.whitespaceund apply.whitespace) dienen nicht zum Entfernen von nachgestellten Leerzeichen, sondern zum:

  • core.whitespace: Erkennen Sie sie und lösen Sie Fehler aus
  • apply.whitespace: und entfernen Sie sie, aber nur während des Patches, nicht "immer automatisch"

Ich glaube, das git hook pre-commitwürde einen besseren Job machen (einschließlich des Entfernens von nachgestellten Leerzeichen).


Beachten Sie, dass Sie jederzeit festlegen können, dass der pre-commitHook nicht ausgeführt werden soll :

  • vorübergehend: git commit --no-verify .
  • permanent: cd .git/hooks/ ; chmod -x pre-commit

Warnung: Standardmäßig verfügt ein pre-commitSkript (wie dieses ) nicht über die Funktion "Nachlauf entfernen", sondern über die Funktion "Warnung" wie:

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

Sie könnten jedoch einen besseren pre-commitHaken bauen , insbesondere wenn Sie Folgendes berücksichtigen:

Das Festschreiben in Git mit nur einigen Änderungen, die dem Staging-Bereich hinzugefügt wurden, führt immer noch zu einer "atomaren" Revision, die möglicherweise nie als Arbeitskopie existiert hat und möglicherweise nicht funktioniert .


Zum Beispiel schlägt Oldman in einer anderen Antwort einen pre-commitHaken vor , der Leerzeichen erkennt und entfernt.
Da dieser Hook den Dateinamen jeder Datei erhält, würde ich empfehlen, bei bestimmten Dateitypen vorsichtig zu sein: Sie möchten keine nachgestellten Leerzeichen in .md(Markdown-) Dateien entfernen !


1
Es stellt sich heraus, dass git davon überzeugt werden kann, Leerzeichen in Ihrer Arbeitskopie über zu apply.whitespacekorrigieren, indem git dazu gebracht wird, Ihre Änderungen an der Arbeitskopie als Patch zu behandeln. Siehe meine Antwort unten .
Ntc2

> "Sie möchten nachgestellte Leerzeichen in .md-Dateien (Markdown) nicht entfernen" - Warum ist das so? Was ist der Zweck des Leerzeichens von Leerzeichen in Markdown-Dateien? Ich habe festgestellt, dass einige .editorconfigDateien eine bestimmte Regel dafür haben.
Friederbluemle

5
@friederbluemle Abhängig von der Art des Abschlags zeigt ein <br>
abschließendes

Die Einstellung core.whitespaceauf trailing-spacewith git configlöst beim gitFestschreiben in 2.5.0 keinen Fehler aus.
Karl Richter

43

Sie können Git dazu verleiten, das Leerzeichen für Sie zu korrigieren, indem Sie Git dazu verleiten, Ihre Änderungen als Patch zu behandeln. Im Gegensatz zu den "Pre-Commit-Hook" -Lösungen fügen diese Lösungen Git Whitespace-Fixing-Befehle hinzu.

Ja, das sind Hacks.


Robuste Lösungen

Die folgenden Git-Aliase stammen von my~/.gitconfig .

Mit "robust" meine ich, dass diese Aliase fehlerfrei ausgeführt werden und das Richtige tun, unabhängig davon, ob der Baum oder der Index verschmutzt sind. Sie funktionieren jedoch nicht, wenn bereits ein interaktives git rebase -iProgramm ausgeführt wird. siehe meine~/.gitconfig für zusätzliche Kontrollen , wenn Sie diese Ecke Fall egal, wo der git add -eTrick am Ende beschrieben funktionieren soll.

Wenn Sie sie direkt in der Shell ausführen möchten, ohne einen Git-Alias ​​zu erstellen, kopieren Sie einfach alles und fügen Sie es zwischen die doppelten Anführungszeichen ein (vorausgesetzt, Ihre Shell ist Bash-ähnlich).

Korrigieren Sie den Index, aber nicht den Baum

Der folgende fixwsGit-Alias ​​behebt alle Leerzeichenfehler im Index, berührt jedoch den Baum nicht:

# 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"

Die Idee ist, git fixwsvorher auszuführen, git commitwenn Sie Leerzeichenfehler im Index haben.

Korrigieren Sie den Index und den Baum

Der folgende fixws-global-tree-and-indexGit-Alias ​​behebt alle Leerzeichenfehler im Index und im Baum, falls vorhanden:

# 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"

Führen Sie folgende Schritte aus, um Leerzeichen in nicht versionierten Dateien zu korrigieren

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

Einfache, aber nicht robuste Lösungen

Diese Versionen sind einfacher zu kopieren und einzufügen, aber sie tun nicht das Richtige, wenn ihre Nebenbedingungen nicht erfüllt sind.

Korrigieren Sie den im aktuellen Verzeichnis verwurzelten Unterbaum (setzt den Index jedoch zurück, wenn er nicht leer ist).

Verwenden Sie git add -e, um die Patches mit dem Identitätseditor zu "bearbeiten" ::

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

Korrigieren und beibehalten Sie den Index (schlägt jedoch fehl, wenn der Baum verschmutzt oder der Index leer ist).

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

Korrigieren Sie den Baum und den Index (setzt den Index jedoch zurück, wenn er nicht leer ist)

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

Erklärung des export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .Tricks

Bevor ich git rebase --whitespace=fixaus dieser Antwort etwas über den Trick erfuhr, benutzte ich git addüberall den komplizierteren Trick.

Wenn wir es manuell gemacht haben:

  1. Setzen Sie apply.whitespaceauf fix(Sie dies nur einmal zu tun haben):

    git config apply.whitespace fix
    

    Dies weist Git an, Leerzeichen in Patches zu korrigieren .

  2. Überzeugen Sie Git, Ihre Änderungen als Patch zu behandeln :

    git add -up .
    

    Drücken Sie a+ enter, um alle Änderungen für jede Datei auszuwählen. Sie erhalten eine Warnung, dass Git Ihre Leerzeichenfehler behebt.
    ( git -c color.ui=auto diffAn dieser Stelle wird angezeigt, dass Ihre nicht indizierten Änderungen genau die Leerzeichenfehler sind.)

  3. Entfernen Sie die Leerzeichenfehler aus Ihrer Arbeitskopie:

    git checkout .
    
  4. Bringen Sie Ihre Änderungen zurück (wenn Sie nicht bereit sind, sie festzuschreiben):

    git reset
    

Das GIT_EDITOR=:Mittel, das :als Editor und als Befehl verwendet werden soll, :ist die Identität.


1
Ich habe es gerade in Windows getestet: Dies funktioniert gut in einer DOS-Eingabeaufforderung: set VISUAL= && git add -ue . && git checkout .Beachten Sie das ' .' verwendet mit git add: das liegt an git1.8.3
VonC

@VonC Wird VISUAL nicht dauerhaft deaktiviert, was z. B. dazu führen kann git commit, dass der falsche Editor später verwendet wird? Ich verpacke das VISUAL=Teil in einer Subshell in meiner Unix-Version oben, um dies zu vermeiden, aber ich weiß nicht, ob DOS Subshells hat.
Ntc2

1
Danke für den tollen Hack! Zu Ihrer Information, wenn Sie festgelegt haben core.editor, hat der Export VISUALkeine Auswirkung, da die Konfigurationseinstellung Vorrang hat man git-var. Um dies zu überschreiben, müssen Sie GIT_EDITOR=:stattdessen exportieren .
Nick Filz

1
Außerdem habe ich meine Version von so fixwsangepasst, dass sie schnell fehlschlägt, wenn Sie sich bereits in einer interaktiven Rebase befinden, da sie sonst an der git rebase --whitespace=fixLeitung stirbt und Sie in einem seltsamen Zustand zurücklässt . Ich habe mir diese Frage geliehen und gerade einen zusätzlichen Fall vor dem if hinzugefügt: 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: Ich habe dies in einen Pre-Commit-Hook umgewandelt
Ian Kelling

29

Ich habe einen Git- Pre-Commit-Hook gefunden, der nachgestellte Leerzeichen entfernt .

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

3
Der zweite sedAufruf ( sed -r 's/:[0-9]+:.*//') könnte durch ersetzt werden cut -f1 -d:. Dies sollte sowohl auf Linux- als auch auf BSD-basierten Plattformen gleich funktionieren.
Ihor Kaharlichenko

2
@IhorKaharlichenko: Tatsächlich ist die Verwendung cutnicht so sicher wie die zweite sed: Der Schnitt schlägt im (höchst unwahrscheinlichen) Fall von Dateinamen fehl, die ":" enthalten. Sie könnten awk 'NF>2{NF-=2}1'sicher sein
MestreLion

1
Übrigens, wenn Sie unter Windows (msysgit) arbeiten und verwenden core.autocrlf=true, möchten Sie möglicherweise dos2unix -D "$FILE"nach sed innerhalb der for-Schleife hinzufügen . Andernfalls werden alle CRLFs in LFs geändert, indem nur sed ausgegeben wird.
Jakub.g

49
Doing git addin einem commit scheint ziemlich böse zu mir. Was ist, wenn Sie eine Datei teilweise bereitstellen / festschreiben? Sie möchten nicht, dass die gesamte Datei hinter Ihrem Rücken festgeschrieben wird, oder?
Stefaan

19

Unter Mac OS (oder wahrscheinlich jedem BSD) müssen die sed-Befehlsparameter geringfügig abweichen. Versuche dies:

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

Speichern Sie diese Datei als .git/hooks/pre-commit- oder suchen Sie nach der Datei , die bereits vorhanden ist, und fügen Sie den unteren Block irgendwo darin ein. Und denken chmod a+xSie auch daran.

Oder für die globale Verwendung (über Git-Commit-Hooks - globale Einstellungen ) können Sie es in $GIT_PREFIX/git-core/templates/hooks(wobei GIT_PREFIX / usr oder / usr / local oder / usr / share oder / opt / local / share ist) einfügen und git initin Ihren vorhandenen Repos ausführen .

Nach git help init:

Das Ausführen von git init in einem vorhandenen Repository ist sicher. Es werden keine Dinge überschrieben, die bereits vorhanden sind. Der Hauptgrund für das erneute Ausführen von git init ist das Abrufen neu hinzugefügter Vorlagen.


7
Ändert dieser Hook nicht die Arbeitsdatei und überschreibt den Index mit der geänderten Arbeitsdatei? Wenn Sie 'git add -p' verwenden würden, um Ihren Index zu erstellen, würde dieser Commit-Hook das umhauen.
Matthew Dutton

2
Ja, du hast wahrscheinlich recht. Möglicherweise muss jemand dieses Skript neu schreiben, um die Munged-Datei zu verwenden git hash-object -wund git update-index(erneut) direkt in den Index einzufügen. Jemand sehr mutig.
AlexChaffee

11

Ich überlasse diese Aufgabe lieber Ihrem Lieblingseditor.

Legen Sie einfach einen Befehl fest, um nachgestellte Leerzeichen beim Speichern zu entfernen.


2
In vim können Sie dies tun mit: autocmd BufWritePre .cpp, .c, *. H:% / \ s \ + $ // e
Robert Massaioli

3
Entschuldigung, ich habe den obigen Kommentar vor dem Testen positiv bewertet. Nach dem Prozentzeichen fehlt ein "s", und der Cursor bewegt sich, wenn Leerzeichen gefunden werden, und das letzte Suchmuster wird entfernt. Weitere Alternativen finden Sie unter vim.wikia.com/wiki/Remove_unwanted_spaces .
Seth Johnson

1
In Emacs ist es Mx delete-trailing-whitespace.
Mauvis Ledford

2
Besser noch, setzen Sie für Emacs einen Hook, um nachfolgende Leerzeichen vor dem Speichern zu löschen, indem Sie sie (add-hook 'before-save-hook 'delete-trailing-whitespace)zu Ihrer .emacsDatei hinzufügen . Emacs Whitespace Tricks
Duncan Parkes

1
Ich verwende (add-hook 'vor-save-hook' Whitespace-Bereinigung), das auch Tabulatoren in Leerzeichen konvertiert.
Nils Fagerburg

10

Verwenden von Git-Attributen und Filter-Setup mit Git-Konfiguration

OK, dies ist ein neuer Ansatz zur Lösung dieses Problems. Mein Ansatz besteht darin, keine Hooks zu verwenden, sondern Filter und Git-Attribute zu verwenden. Auf diese Weise können Sie auf jedem Computer, auf dem Sie entwickeln, eine Reihe von Filtern einrichten, die zusätzliche nachgestellte Leerzeichen und zusätzliche Leerzeilen am Ende der Dateien entfernen, bevor Sie sie festschreiben. Richten Sie dann eine .gitattributes-Datei ein, die angibt, auf welche Dateitypen der Filter angewendet werden soll. Die Filter haben zwei Phasen, cleandie beim Hinzufügen von Dateien zum Index und smudgebeim Hinzufügen zum Arbeitsverzeichnis angewendet werden.

Sagen Sie Ihrem Git, er soll nach einer globalen Attributdatei suchen

Weisen Sie zunächst Ihre globale Konfiguration an, eine globale Attributdatei zu verwenden:

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

Erstellen Sie globale Filter

Erstellen Sie nun den Filter:

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

Fügen Sie die sed scripting Magie hinzu

Fügen Sie das fixup-eol-eofSkript schließlich irgendwo in Ihren Pfad ein und machen Sie es ausführbar. Das Skript verwendet sed, um einige Änderungen im laufenden Betrieb vorzunehmen (Leerzeichen und Leerzeichen am Zeilenende und überflüssige Leerzeilen am Ende der Datei entfernen).

fixup-eol-eof sollte folgendermaßen aussehen:

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

Mein Kern davon

Teilen Sie git mit, auf welche Dateitypen Ihr neu erstellter Filter angewendet werden soll

Zuletzt erstellen oder öffnen Sie ~ / .gitattributes_global in Ihrem bevorzugten Editor und fügen Sie Zeilen hinzu wie:

pattern attr1 [attr2 [attr3 […]]]

Wenn wir also das Whitespace-Problem beheben möchten, fügen wir für alle unsere c-Quelldateien eine Zeile hinzu, die folgendermaßen aussieht:

*.c filter=fix-eol-eof

Diskussion des Filters

Der Filter besteht aus zwei Phasen: der Bereinigungsphase, die angewendet wird, wenn Dinge zum Index hinzugefügt oder eingecheckt werden, und der Verwischungsphase, wenn Git Dinge in Ihr Arbeitsverzeichnis legt. Hier führt unser Fleck nur den Inhalt durch den catBefehl aus, wodurch er unverändert bleiben soll, mit der Ausnahme, dass möglicherweise ein nachfolgendes Zeilenumbruchzeichen hinzugefügt wird, wenn am Ende der Datei kein Zeichen vorhanden ist. Der Befehl clean ist die Whitespace-Filterung, die ich aus Notizen unter http://sed.sourceforge.net/sed1line.txt zusammengestellt habe . Es scheint, dass es in ein Shell-Skript eingefügt werden muss. Ich konnte nicht herausfinden, wie der Befehl sed eingefügt werden soll, einschließlich der Bereinigung der zusätzlichen Zeilen am Ende der Datei direkt in die git-config-Datei. (Sie CANEntfernen Sie nachgestellte Leerzeichen, ohne dass ein separates sed-Skript erforderlich ist. Setzen Sie das einfach filter.fix-eol-eofauf etwas, sed 's/[ \t]*$//' %fbei dem \tes sich um eine tatsächliche Registerkarte handelt, indem Sie die Tabulatortaste drücken.)

Mit require = true wird ein Fehler ausgelöst, wenn etwas schief geht, damit Sie keine Probleme haben.

Bitte vergib mir, wenn meine Sprache in Bezug auf Git ungenau ist. Ich denke, ich habe ein ziemlich gutes Verständnis für die Konzepte, lerne aber immer noch die Terminologie.


Interessanter Ansatz. +1
VonC

Danke @VonC! Ich möchte diese Gelegenheit auch nutzen, um darauf hinzuweisen, dass die Git-Attribute pro .gitOrdner pro Ordner und nicht global konfiguriert werden können , was möglicherweise sinnvoller ist.
Zbeekman

9

Ich habe diesen Pre-Commit-Hook geschrieben, der nur den nachgestellten Leerraum aus den Zeilen entfernt, die Sie geändert / hinzugefügt haben, da die vorherigen Vorschläge dazu neigen, unlesbare Commits zu erstellen, wenn die Zieldateien zu viel nachgestellten Leerraum haben.

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

1
Interessant. +1. Siehe meine andere Antwort zur Berechnung des leeren Baums.
VonC

1
Gute Idee, genau das würde ich mir wünschen. Seien Sie jedoch vorsichtig, wenn Sie dies verwenden! Für mich unter OSX und Git Version 2.3.5 werden alle von mir bereitgestellten zusätzlichen, aber nicht festgeschriebenen Änderungen weggeblasen. Ich wäre trotzdem an einer funktionierenden Lösung dafür interessiert.
Casper

9

Bitte versuchen Sie es mit meinen Pre-Commit- Hooks . Sie können nachgestellte Leerzeichen automatisch erkennen und entfernen . Danke dir!

es kann funktionieren unter GitBash(windows), Mac OS X and Linux!


Schnappschuss:

$ 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(-)

1
Interessant. +1. Ich habe Ihren Haken in meiner eigenen Antwort
verwiesen

@VonC Danke für deine Bestätigung! Zu der '.md' habe ich nur git commit -no-verifyirgendwelche Vorschläge gefunden?
Oldman

Ich würde den Hook lieber in die Lage versetzen, .mdDateien zu erkennen und die Leerzeichen nicht zu entfernen, anstatt den Endbenutzer zu bitten, eine --no-verifyOption auf dem hinzuzufügen git commit.
VonC


6

Hier ist eine Ubuntu + Mac OS X-kompatible Version:

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

Habe Spaß


Sieht so aus, als ob der einzige Unterschied zwischen Ihrem und meinem darin besteht, dass Sie überprüfen, ob sed tatsächlich etwas ersetzt, bevor Sie die Datei neu schreiben ... Ich bin mir nicht sicher, ob dies wichtig ist, da git keine Änderungen festschreibt, die eigentlich nichts ändern. Ich nehme an, es ist geringfügig sicherer, aber auch geringfügig langsamer, und ich bevorzuge die Klarheit, die regulären Ausdrücke nicht zweimal in einer Zeile zu wiederholen. De gustibus non disputandum est!
AlexChaffee

Nein, der Unterschied besteht darin, dass die Version zuerst die Ubuntu-Syntax und danach (falls dies fehlschlägt) die Osx-Syntax verwendet.
Sdepold

1
Ich habe den Beitrag von sdepold bearbeitet. Er sollte jetzt auch Leerzeichen in Dateinamen zulassen können.
Imme

5

Ich habe heute darüber nachgedacht. Das ist alles, was ich für ein Java-Projekt getan habe:

egrep -rl ' $' --include *.java *  | xargs sed -i 's/\s\+$//g'

3

Für Benutzer von Sublime Text .

Stellen Sie Folgendes in Ihrer Setting-User- Konfiguration richtig ein .

"trim_trailing_white_space_on_save": true


1
Ist es eine Möglichkeit, dies nach Dateityp festzulegen? Ich habe *.md(Markdown-) Dateien, die zum Markieren einer einfachen Datei auf "" (nachfolgende doppelte Leerzeichen) angewiesen sind <br />, und diese Einstellung scheint für alle Dateien zu gelten , einschließlich derjenigen, bei denen ich die nachfolgenden Leerzeichen nicht entfernen möchte.
VonC

@VonC Es gibt eine Hierarchie, wie die Konfiguration angewendet wird. Weitere Details finden Sie hier. Stackoverflow.com/questions/16983328/… Ich hoffe, es hilft
Haris Krajina

2

Die for-Schleife für Dateien verwendet die Shell-Variable $ IFS. In dem angegebenen Skript werden Dateinamen mit einem Zeichen, das sich ebenfalls in der Variablen $ IFS befindet, als zwei verschiedene Dateien in der for-Schleife angezeigt. Dieses Skript behebt das Problem: Der Multiline-Modus-Modifikator, wie er in sed-manual angegeben ist, scheint auf meiner Ubuntu-Box nicht standardmäßig zu funktionieren. Daher habe ich nach einer anderen Implementierung gesucht und diese mit einem iterierenden Label gefunden. Im Wesentlichen wird die Substitution nur auf der letzte Zeile der Datei, wenn ich es richtig verstanden habe.

#!/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-subsition-Muster: Wie kann ich eine neue Zeile (\ n) durch sed ersetzen? .


2

Dies entfernt Leerzeichen vor einem Commit nicht automatisch , ist jedoch recht einfach durchzuführen. Ich habe das folgende Perl-Skript in eine Datei mit dem Namen git-wsf (git whitespace fix) in einem Verzeichnis in $ PATH eingefügt, damit ich Folgendes tun kann:

git wsf | Sch

und es entfernt alle Leerzeichen nur aus Dateizeilen, die git als Diff melden.

#! /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";
}

0

Etwas spät, aber da dies jemandem da draußen helfen könnte, geht es los.

Öffnen Sie die Datei in VIM. Geben Sie Folgendes in die vim-Befehlszeile ein, um Tabulatoren durch Leerzeichen zu ersetzen

:%s#\t#    #gc

Andere nachlaufende Leerzeichen loswerden

:%s#\s##gc

Das hat es so ziemlich für mich getan. Es ist mühsam, wenn Sie viele Dateien bearbeiten müssen. Aber ich fand es einfacher, als Hooks vorab festzuschreiben und mit mehreren Editoren zu arbeiten.


Wenn es zu langweilig wird - und wenn Sie eine Sicherungskopie dessen haben, was Sie bearbeiten möchten -, verwende ich oft nur sed, um Tabulatoren in Leerzeichen zu ändern: sed -i 's|\t| |g' filenames(Leerzeichen in der Ersetzungsposition). Beachten Sie, dass Sie find verwenden können, um Ihre Dateinamen abzurufen. Wenn Sie nicht darüber nachgedacht haben, wie Sie dieses Backup erhalten können, schreibe ich normalerweise einfach alles fest und mache das Commit dann mit einem Soft-Reset wieder rückgängig. Manchmal füge ich alles zum Baum hinzu, aber schreibe nicht fest, und manchmal verwende ich den Stash / Apply (nicht Pop!). Wenn ich Angst habe, synchronisiere ich meinen gesamten Baum an einen sicheren Ort, bevor ich mich einmische ...
Salbei

0

Verwenden Sie Folgendes, um nachgestellte Leerzeichen am Zeilenende in einer Datei portabel zu löschen ed:

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

-1

Dies wird Ihr Problem wahrscheinlich nicht direkt lösen, aber Sie möchten diese möglicherweise über git-config in Ihrem tatsächlichen Projektbereich festlegen, der ./.git/config im Gegensatz zu ~ / .gitconfig bearbeitet. Schön, dass die Einstellungen unter allen Projektmitgliedern konsistent bleiben.

git config core.whitespace "trailing-space,space-before-tab"
git config apply.whitespace "trailing-space,space-before-tab"

3
afaik, Einstellungen in .git werden nicht mit anderen geteilt; Sie sind spezifisch für Ihr lokales Repo
AlexChaffee
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.