Fügen Sie nur Änderungen hinzu, die keine Leerzeichen sind

343

Ich habe meinen Texteditor, um nachgestellte Leerzeichen beim Speichern einer Datei automatisch zu kürzen, und ich trage zu einem Open-Source-Projekt bei, das schwerwiegende Probleme mit nachgestellten Leerzeichen hat.

Jedes Mal, wenn ich versuche, einen Patch einzureichen, muss ich zuerst alle Nur-Leerzeichen-Änderungen von Hand ignorieren, um nur die relevanten Informationen auszuwählen. Nicht nur das, aber wenn ich renne, stoße git rebaseich normalerweise auf mehrere Probleme.

Als solches möchte ich in der Lage sein, nur Nicht-Leerzeichen-Änderungen zum Index hinzuzufügen, ähnlich wie dies der git add -pFall ist, ohne jedoch alle Änderungen selbst auswählen zu müssen.

Weiß jemand, wie man das macht?

BEARBEITEN: Ich kann die Funktionsweise des Projekts nicht ändern, und sie haben beschlossen, dies zu ignorieren, nachdem sie es auf der Mailingliste besprochen haben.

Edu Felipe
quelle

Antworten:

395

Die @ Frew-Lösung war nicht ganz das, was ich brauchte, daher ist dies der Alias, den ich für genau das gleiche Problem erstellt habe:

alias.addnw=!sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero -'

Oder Sie können einfach ausführen:

git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero -

Aktualisieren

Gemäß diesem Kommentar wurden Optionen hinzugefügt -U0, um --unidiff-zeroProbleme mit der Kontextübereinstimmung zu umgehen .

Grundsätzlich wird der Patch angewendet, der addohne Änderungen an Leerzeichen angewendet wird . Sie werden feststellen, dass nach einer git addnw your/filenoch nicht bereitgestellten Änderung die Leerzeichen übrig bleiben.

Die --no-Farbe ist nicht erforderlich, aber da ich die Farben immer eingestellt habe, muss ich sie verwenden. Wie auch immer, besser sicher als leid.

Colin Hebert
quelle
7
Dies funktionierte gut für mich, aber ich musste es verwenden, git apply --ignore-whitespacesonst würde der Patch aus offensichtlichen Gründen nicht gelten.
10.
106
Es sollte wirklich eine Option geben, um git hinzuzufügen, so git add -wtat dies.
Jarl
7
Das gibt mir Probleme mit patch does not applyund error while searching for... Irgendwelche Ideen?
DTI-Matt
18
hat bei mir nicht funktioniert. Ich habe einen patch does not applyFehler erhalten.
Jerry Saravia
13
Wenn Sie aufgrund von Leerzeichen im Kontext "Patch fehlgeschlagen" erhalten, wie @bronson hervorhebt, funktioniert dieser überarbeitete Befehl (Er generiert einen Patch ohne Kontext) : git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero. Dies ist nicht riskant, da der Index bereits so aktuell wie möglich ist und somit eine zuverlässige Basis für den Patch darstellt.
void.pointer
36

Das funktioniert bei mir:

Wenn Sie einen Vorrat behalten möchten, funktioniert dies

git stash && git stash apply && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

Ich mag die Stashes nicht, aber ich bin auf einen Fehler in git + cygwin gestoßen, bei dem ich Änderungen verliere. Um sicherzustellen, dass die Dinge zumindest zum Reflog gingen, habe ich Folgendes eingerichtet:

git add . && git commit -am 'tmp' && git reset HEAD^ && git diff -w > foo.patch && git checkout . && git apply foo.patch && rm foo.patch

Grundsätzlich erstellen wir ein Diff, das die Leerzeichenänderungen nicht enthält, setzen alle unsere Änderungen zurück und wenden dann das Diff an.

Frew Schmidt
quelle
1
+1. Möglicherweise möchten Sie git stashstatt Auschecken eine Sicherungskopie Ihrer Änderungen erstellen, zumindest bis diese getestet wurden.
Paŭlo Ebermann
1
Sie werden am Ende eine Menge Verstecke haben und im Grunde müssen Sie das alles nicht wirklich tun. Es funktioniert, aber ich denke, es ist ein bisschen chaotisch
Colin Hebert
3
Ich stimme Colin zu. Wenn das Skript funktioniert, sollte es nicht erforderlich sein, einen Stash zu erstellen. Was jedoch in Betracht gezogen werden könnte, wäre, Stash und dann Stash Pop auszuführen. Popped Stashes können bei Bedarf wiederhergestellt werden, aber sonst werden Sie nicht viele Stashes haben. Dies lässt auch eine zusätzliche Datei herumliegen
Casebash
Wie wäre es mit dem Überspringen von Binärdateien? Beim Versuch, das obige Snippet anzuwenden, wird die Fehlermeldung angezeigt, dass der Patch ohne die vollständige Indexzeile nicht angewendet werden kann! Was mich schlägt ist, dass ich diese Dateien / Binärdateien überhaupt nicht berührt habe!
tver3305
1
Ich denke am Ende des ersten Befehls sollte "git rm foo.patch" nur "rm foo.patch" sein. Ansonsten sehr hilfreich danke.
Jack Casey
33

Erstellen Sie eine Patch-Datei, die nur die tatsächlichen Änderungen enthält (ausgenommen Zeilen mit nur Leerzeichenänderungen), bereinigen Sie dann Ihren Arbeitsbereich und wenden Sie diese Patch-Datei an:

git diff> backup
git diff -w> Änderungen
git reset --hard
patch <Änderungen

Überprüfen Sie die verbleibenden Unterschiede dann addund commitwie gewohnt.

Das Äquivalent für Mercurial lautet:

hg diff> backup
hg diff -w> Änderungen
hg revert --all
hg import --no-commit Änderungen

Steve Pitchers
quelle
Was ist eine "geschützte" Frage? und ich auch Antworten. Ich glaube nicht, dass dies auch nur eine Antwort für mich ist, da die Frage anscheinend aus dem
Nichts
4
@jww Der Kern der Frage des Originalplakats lautet: "Wie kann vermieden werden, dass nur Leerzeichen an der Quellcodeverwaltung geändert werden?". Das OP verwendet zufällig Git, aber dies gilt auch für jedes Quellcodeverwaltungssystem, das ich jemals verwendet habe. Diese Antwort zeigt das richtige Verfahren, wenn jemand Mercurial verwendet. Ich könnte mir vorstellen, dass jemand anderes auch eine Lösung für Leute mit Sublesion usw. beisteuert
Steve Pitchers
1
@jww und @ pagid: Ich habe meine Antwort bearbeitet, um Git speziell anzusprechen, und dabei denselben Ansatz wie meine Lösung für Mercurial verwendet. Aus meiner Sicht ist StackOverflow mehr als nur ein weiteres Q + A-Forum - es spielt auch eine Rolle als Wissensspeicher. Andere Personen als das Originalplakat können von den gegebenen Antworten profitieren, und ihre Umstände variieren. Aus diesem Grund glaube ich, dass Antworten, die ein allgemeines Prinzip vermitteln, gültig sind, anstatt nur auf eine bestimmte Situation abzuzielen.
Steve Pitchers
@Steve - "Ich habe meine Antwort bearbeitet, um Git speziell anzusprechen ..." - warum hast du im Kontext von mercurial keine neue Frage gestellt und dann deine eigene Antwort auf die neue Frage hinzugefügt ???
JWW
8
Dies ist tatsächlich der sauberste, verständlichste und unzerbrechlichste der Ansätze, die ich gesehen habe.
Kzqai
12

Die Antwort mit der höchsten Bewertung funktioniert nicht in allen Fällen, da die Benutzer in den Kommentaren Leerzeichen im Patch-Kontext verwenden.

Ich habe den Befehl wie folgt überarbeitet:

$ git diff -U0 -w --no-color | git apply --cached --ignore-whitespace --unidiff-zero

Dies erzeugt einen Patch ohne Kontext. Sollte kein Problem sein, da der Patch nur von kurzer Dauer ist.

Entsprechender Alias, erneut eine Überarbeitung dessen, was bereits von anderen Benutzern bereitgestellt wurde:

addw = !sh -c 'git diff -U0 -w --no-color "$@" | git apply --cached --ignore-whitespace --unidiff-zero' -
void.pointer
quelle
Um nur Einrückungsänderungen zu ignorieren, musste ich --ignore-space-changestattdessen verwenden -w. git diff -U0 --ignore-space-change --no-color | git apply --cached --unidiff-zero
Andy
Ein Wort der Warnung, diesen schönen Trick ohne Kontext nicht mit --ignore-blank-linesanderen zu verwenden. Sie werden feststellen, dass Diff-Chunks mit falschen Offsets gepatcht werden, wenn einige der Änderungen des Leerraums, die Sie ignorieren möchten, das Entfernen / Hinzufügen von Leerzeilen sind.
Elbeardmorez
12

Fügen Sie Folgendes hinzu .gitconfig:

anw = !git diff -U0 -w --no-color -- \"$@\" | git apply --cached --ignore-whitespace --unidiff-zero "#"

Vielen Dank an @Colin Herberts Antwort für die Inspiration.

Syntax Erläuterung

Das Finale #muss in Anführungszeichen gesetzt werden, damit es nicht .gitconfigals Kommentar in der Shell behandelt wird, sondern durchgereicht wird und als Kommentar in der Shell behandelt wird. Es wird zwischen dem Ende des git applyund den vom Benutzer angegebenen Argumenten eingefügt , die gitautomatisch am platziert werden Ende der Befehlszeile. Diese Argumente sind hier nicht erwünscht - wir wollen sie nicht git applyverbrauchen, daher das vorhergehende Kommentarzeichen. Möglicherweise möchten Sie diesen Befehl ausführen GIT_TRACE=1 git anw, um dies in Aktion zu sehen.

Das --Signal endet mit Argumenten und berücksichtigt den Fall, dass Sie eine Datei mit dem Namen -woder etwas haben, zu dem ein Wechsel aussehen würde git diff.

Es sind doppelte Anführungszeichen $@erforderlich, um vom Benutzer angegebene Anführungszeichen zu erhalten. Wenn die" Zeichen nicht maskiert wird, wird es vom .gitconfigParser verbraucht und erreicht die Shell nicht.

Hinweis: .gitconfigAlias - Parsing Apostrophe als etwas Besonderes nicht erkennt - seine einzigen Sonderzeichen sind ", \, \nund ;(außerhalb eines "-quoted string). Dies ist der Grund, warum ein "Muss immer maskiert werden muss, auch wenn es so aussieht, als ob es sich in einem String in einfachen Anführungszeichen befindet (worüber Git völlig agnostisch ist).

Dies ist wichtig, z. Wenn Sie einen praktischen Alias ​​haben, um einen bashBefehl im Stammverzeichnis des Arbeitsbaums auszuführen . Die falsche Formulierung lautet:

sh = !bash -c '"$@"' -

Während der richtige ist:

sh = !bash -c '\"$@\"' -
Tom Hale
quelle
Ausgezeichnet. Dadurch konnte ich jeweils eine Datei hinzufügen. Gibt es neben dem Hinzufügen eines Stammverzeichnisses für ein Argument eine Möglichkeit, diese Funktion wie "git add -A" auszuführen?
Chucky
7

Wie wäre es mit folgendem:

git add `git diff -w --ignore-submodules |grep "^[+][+][+]" |cut -c7-`

Der Befehl in Backquotes ruft die Namen von Dateien ab, deren Nicht-Leerzeichen geändert wurden.

Karmakaze
quelle
2
oder nur git add `git diff -w |grep '^+++' |cut -c7-`wenn Submodule nicht verwendet werden
Karmakaze
-1

Sie sollten zuerst überlegen, ob das nachfolgende Leerzeichen beabsichtigt ist. Viele Projekte, darunter der Linux-Kernel, Mozilla, Drupal und Kerberos (um nur einige auf der Wikipedia-Seite zum Thema Stil zu nennen), verbieten das Nachstellen von Leerzeichen. Aus der Linux-Kerneldokumentation:

Holen Sie sich einen anständigen Editor und lassen Sie keine Leerzeichen am Zeilenende.

In Ihrem Fall ist das Problem umgekehrt: Frühere Commits (und möglicherweise aktuelle) haben diese Richtlinie nicht befolgt.

Ich würde wetten, dass niemand wirklich das nachgestellte Leerzeichen will, und die Behebung des Problems könnte eine willkommene Änderung sein. Bei anderen Benutzern tritt möglicherweise das gleiche Problem auf wie bei Ihnen. Es ist auch wahrscheinlich, dass die Mitwirkenden, die nachgestellte Leerzeichen hinzufügen, nicht wissen, dass sie dies tun.

Anstatt zu versuchen, git neu zu konfigurieren, um das Problem zu ignorieren, oder die ansonsten wünschenswerte Funktionalität in Ihrem Editor zu deaktivieren, würde ich mit einem Beitrag auf der Projekt-Mailingliste beginnen, in dem das Problem erläutert wird. Viele Editoren (und Git selbst) können so konfiguriert werden, dass sie mit nachgestellten Leerzeichen umgehen.

Kevin Vermeer
quelle
16
Es ist nicht beabsichtigt, aber ich kann die Art und Weise, wie mehr als 100 Personen, die zum Projekt beitragen, denken, nicht ändern. Sie haben nichts dagegen und akzeptieren keine Patches mit mehr als 1000 Änderungen, die sich nur mit nachgestellten Leerzeichen befassen. Sie kennen das Problem und haben beschlossen, es zu ignorieren. Diese Diskussion fand bereits in der Liste statt und wurde geschlossen. In diesem Fall muss ich mich an sie anpassen.
Edu Felipe
19
Konfigurieren Sie dann Ihren Editor so, dass bei der Arbeit am Code dieses Projekts keine nachgestellten Leerzeichen abgeschnitten werden.
Jamessan
-2

Ich habe einen Git- Pre-Commit-Hook gefunden, der nachgestellte Leerzeichen entfernt . Wenn Sie jedoch andere nicht dazu bringen können, dies zu verwenden, ist dies möglicherweise keine gültige Lösung.

  #!/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"
  done
  exit
cmcginty
quelle
4
In dieser Frage wird gefragt, wie nachgestellte Leerzeichen beibehalten werden sollen.
Douglas
@ Douglas: Man könnte diese Antwort wahrscheinlich verwenden, um ein Commit für einen temporären Zweig zu erstellen, den echten Patch dort festzuschreiben und den Diff nur irgendwie in den funktionierenden Zweig zu pflücken ...
Tobias Kienzler