Ich benutze git mit meinem Team und möchte Whitespace-Änderungen aus meinen Diffs, Protokollen, Zusammenführungen usw. entfernen. Ich gehe davon aus, dass der einfachste Weg dies zu tun darin besteht, dass git abschließende Whitespaces (und andere Whitespace-Fehler) automatisch entfernt ) von allen Commits, wie sie angewendet werden.
Ich habe versucht, Folgendes per ~/.gitconfig
- Datei hinzuzufügen, aber beim Festschreiben wird nichts ausgeführt. Vielleicht ist es für etwas anderes konzipiert. Was ist die Lösung?
[core]
whitespace = trailing-space,space-before-tab
[apply]
whitespace = fix
Ich verwende Ruby für den Fall, dass jemand irgendwelche Ruby spezifische Ideen hat. Die automatische Formatierung des Codes vor dem Festschreiben wäre der nächste Schritt, aber das ist ein schweres Problem und nicht wirklich ein großes Problem verursacht.
Diese Einstellungen (core.whitespace
Und apply.whitespace
) Dienen nicht zum Entfernen von nachgestellten Leerzeichen, sondern zum:
core.whitespace
: Erkennen Sie diese und lösen Sie Fehler ausapply.whitespace
: Und entferne sie, aber nur während des Patches, nicht "immer automatisch"Ich glaube, das git hook pre-commit
würde einen besseren Job dafür machen (beinhaltet das Entfernen von nachgestellten Leerzeichen)
Beachten Sie, dass Sie jederzeit festlegen können, dass der Hook pre-commit
Nicht ausgeführt werden soll:
git commit --no-verify .
cd .git/hooks/ ; chmod -x pre-commit
Warnung: Standardmäßig hat ein pre-commit
- Skript (wie dieses ) nicht eine Funktion zum Entfernen nachgestellter Zeichen, aber eine Warnung. Funktion wie:
if (/\s$/) {
bad_line("trailing whitespace", $_);
}
Sie können jedoch einen besseren pre-commit
- Hook erstellen, 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 oldmanin einer anderen Antwort einen pre-commit
- Haken 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 abschließende Leerzeichen in .md
- Dateien (Markdown) nicht entfernen!
Sie können Git dazu verleiten, das Leerzeichen für Sie zu reparieren, 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.
Die folgenden Git-Aliase stammen aus 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 -i
Ausgeführt wird. Siehe mein ~/.gitconfig
für zusätzliche Überprüfungen, ob Sie sich für diesen Eckfall interessieren, in dem der am Ende beschriebene git add -e
- Trick funktionieren sollte.
Wenn Sie sie direkt in der Shell ausführen möchten, ohne einen Git-Alias zu erstellen, kopieren Sie einfach alles in doppelte Anführungszeichen und fügen Sie es ein (vorausgesetzt, Ihre Shell ist Bash-artig).
Der folgende fixws
Git-Alias behebt alle Whitespace-Fehler im Index, sofern vorhanden, ohne jedoch die Struktur zu berühren:
# 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 fixws
Vor git commit
Auszuführen, wenn der Index Leerzeichen enthält.
Der folgende Git-Alias fixws-global-tree-and-index
Behebt alle Whitespace-Fehler im Index und in der Baumstruktur, 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 Folgendes aus, um auch Leerzeichen in nicht versionierten Dateien zu korrigieren
git add --intent-to-add <unversioned files> && git fixws-global-tree-and-index
Diese Versionen sind einfacher zu kopieren und einzufügen, aber sie tun nicht das Richtige, wenn ihre Nebenbedingungen nicht erfüllt sind.
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
git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset --soft HEAD~
git add -u :/ && git commit -m TEMP && git rebase --whitespace=fix HEAD~ && git reset HEAD~
export GIT_EDITOR=: && git -c apply.whitespace=fix add -ue .
Bevor ich den git rebase --whitespace=fix
- Trick durch diese Antwort kennengelernt habe, habe ich überall den komplizierteren git add
- Trick verwendet.
Wenn wir es manuell gemacht haben:
Setzen Sie apply.whitespace
Auf fix
(Sie müssen dies nur einmal tun):
git config apply.whitespace fix
Dies weist Git an, Leerzeichen in Patches zu korrigieren.
Überzeugen Sie Git, Ihre Änderungen als Patch zu behandeln:
git add -up .
Schlagen a+enterum alle Änderungen für jede Datei auszuwählen. Sie erhalten eine Warnung, dass Git Ihre Whitespace-Fehler behebt.
(git -c color.ui=auto diff
An dieser Stelle zeigt, dass Ihre nicht indizierten Änderungen genau die Leerzeichenfehler sind).
Entfernen Sie die Whitespace-Fehler aus Ihrer Arbeitskopie:
git checkout .
Bringen Sie Ihre Änderungen zurück (wenn Sie nicht bereit sind, sie festzuschreiben):
git reset
GIT_EDITOR=:
Bedeutet, :
Als Editor zu verwenden, und als Befehl ist :
Die Identität.
Ich habe einen git Pre-Commit-Hook, der nachfolgende Leerzeichen entfernt gefunden.
#!/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
Unter Mac OS (oder wahrscheinlich einem BSD) müssen sich die sed-Befehlsparameter geringfügig unterscheiden. 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 die Datei, die bereits vorhanden ist, und fügen Sie den unteren Teil irgendwo hinein. Und denken Sie daran, es auch zu chmod a+x
.
Oder für die globale Verwendung (über Git-Commit-Hooks - globale Einstellungen ) können Sie es in $GIT_PREFIX/git-core/templates/hooks
Einfügen (wobei GIT_PREFIX/usr oder/usr/local oder/usr/share oder/opt ist/local/share) und führen Sie git init
in Ihren vorhandenen Repos aus.
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 die erneute Ausführung von git init besteht darin, neu hinzugefügte Vorlagen zu übernehmen.
Ich überlasse diese Aufgabe lieber Ihrem Lieblingsredakteur.
Setzen Sie einfach einen Befehl, um nachgestellte Leerzeichen beim Speichern zu entfernen.
Bitte versuchen Sie meine Pre-Commit Hooks , es kann automatisch abschließende Leerzeichen erkennen und entferne es. Vielen Dank!
es kann unter GitBash(windows), Mac OS X and Linux
arbeiten!
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(-)
Ich habe diesen Pre-Commit-Hook geschrieben, der nur den nachgestellten Leerraum aus den von Ihnen geänderten/hinzugefügten Zeilen entfernt, 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
OK, dies ist ein neuer Ansatz zur Lösung dieses Problems. Mein Ansatz ist, keine Hooks zu verwenden, sondern Filter und Git-Attribute zu verwenden. Damit können Sie auf jedem Computer, auf dem Sie entwickeln, eine Reihe von Filtern einrichten, die zusätzliche Leerzeichen und Leerzeilen am Ende der Dateien entfernen, bevor Sie sie festschreiben. Richten Sie dann eine .gitattributes-Datei ein, in der angegeben ist, auf welche Dateitypen der Filter angewendet werden soll. Die Filter bestehen aus zwei Phasen: clean
, die beim Hinzufügen von Dateien zum Index angewendet werden, und smudge
, die beim Hinzufügen zum Arbeitsverzeichnis angewendet werden.
Weisen Sie zuerst Ihre globale Konfiguration an, eine globale Attributdatei zu verwenden:
git config --global core.attributesfile ~/.gitattributes_global
Erstellen Sie jetzt 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
Schließlich setzen Sie die fixup-eol-eof
Skript irgendwo auf Ihrem Pfad, und machen Sie es ausführbar. Das Skript verwendet sed, um einige Änderungen im Handumdrehen vorzunehmen (Leerzeichen und Leerzeichen am Zeilenende und überflüssige Leerzeichen am Ende der Datei entfernen).
fixup-eol-eof sollte so aussehen:
#!/bin/bash
sed -e 's/[ ]*$//' -e :a -e '/^\n*$/{$d;N;ba' -e '}' $1
Zuletzt erstellen oder öffnen Sie ~/.gitattributes_global in Ihrem Lieblingseditor und fügen Sie folgende Zeilen hinzu:
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 wie folgt aussieht:
*.c filter=fix-eol-eof
Der Filter hat zwei Phasen, die Bereinigungsphase, die angewendet wird, wenn Dinge zum Index hinzugefügt oder eingecheckt werden, und die Verschmierungsphase, wenn git Dinge in Ihr Arbeitsverzeichnis legt. In diesem Fall führt unser Smudge lediglich den Inhalt über den Befehl cat
aus, der sie unverändert lassen sollte, mit der Ausnahme, dass möglicherweise ein nachgestelltes Zeilenumbruchzeichen hinzugefügt wird, falls am Ende der Datei kein vorhanden war. Der Befehl clean ist die Whitespace-Filterung, die ich aus Notizen unter http://sed.sourceforge.net/sed1line.txt zusammengesetzt habe. Es scheint, dass es in ein Shell-Skript eingefügt werden muss. Ich konnte nicht herausfinden, wie der sed-Befehl eingefügt werden soll, einschließlich der Bereinigung der überflüssigen zusätzlichen Zeilen am Ende der Datei direkt in die git-config-Datei. (Sie [~ # ~] können [~ # ~] abschließende Leerzeichen entfernen, ohne dass ein separates sed-Skript erforderlich ist das filter.fix-eol-eof
zu etwas wie sed 's/[ \t]*$//' %f
bei dem die \t
ist eine aktuelle Registerkarte, indem Sie die Tabulatortaste drücken.)
Mit require = true wird ein Fehler ausgelöst, wenn etwas schief geht, um Probleme zu vermeiden.
Bitte verzeihen Sie mir, wenn meine Sprache in Bezug auf Git ungenau ist. Ich glaube, ich habe ein ziemlich gutes Verständnis für die Konzepte, lerne aber immer noch die Terminologie.
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ß
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'
Für Erhabener Text Benutzer.
Stellen Sie Folgendes in Ihrer Setting-User Konfiguration richtig ein.
"trim_trailing_white_space_on_save": true
die for-Schleife für Dateien verwendet die Shell-Variable $ IFS. Im angegebenen Skript werden Dateinamen mit einem darin enthaltenen Zeichen, das sich auch in der $ IFS-Variablen 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 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 pattern: Wie kann ich eine neue Zeile (\ n) mit sed ersetzen? .
Dies entfernt nicht das Leerzeichen automatisch vor einem Commit, aber es ist ziemlich einfach zu bewirken. Ich habe das folgende Perl-Skript in eine Datei mit dem Namen git-wsf (git whitespace fix) in ein Verzeichnis in $ PATH geschrieben, damit ich:
git wsf | Sch
und es entfernt alle Leerzeichen nur aus Zeilen von Dateien, die git als Diff ausgibt.
#! /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";
}
Verwenden Sie ed
, um abschließende Leerzeichen am Zeilenende einer Datei portabel zu löschen:
test -s file &&
printf '%s\n' H ',g/[[:space:]]*$/s///' 'wq' | ed -s file
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 nachgestellte Leerzeichen entfernen
:%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.