Kann Git eine bestimmte Zeile ignorieren?

112

Ich verwende git, um mit phonegap zu synchronisieren, während ich im nativen Browser des Telefons teste. Als solches habe ich die folgende Zeile:

var isPhoneGap = false;

Natürlich ändere ich dies beim Erstellen, aber gibt es eine Möglichkeit, git so einzurichten, dass diese eine Zeile ignoriert wird, oder muss ich sie in eine eigene Datei einfügen und auf diese Weise ignorieren?

Ich verwende Gitx und das Terminal unter OSX 10.6.

Iolo
quelle
@ user494461: Git Filter ist der Weg, um es zu tun: stackoverflow.com/a/16244970/520162
eckes
1
Können Sie die Umgebung nicht erkennen und eine Umgebungskonfigurationsdatei verwenden?
Exussum
Kurz gesagt: Nein. Aber ich habe ein Präprozessorskript geschrieben, das nach bestimmten kommentierten Codes sucht und diese vor der Veröffentlichung in git entfernt. Überprüfen Sie es hier: github.com/franklinchou/ahk_config/blob/master/preprocess.sh
Franklin

Antworten:

102

Wenn Ihre Datei von einem bestimmten Typ ist, können Sie einen Inhaltsfiltertreiber deklarieren , den Sie in einer .gitattributesDatei deklarieren können (wie in der "Keyword-Erweiterung" von " Git-Attribute " dargestellt):

http://git-scm.com/figures/18333fig0702-tn.png

*.yourType filter=yourFilterName

(Sie können diesen Filter sogar für eine bestimmte Datei festlegen , wenn Sie möchten)

Implementieren:

  • yourFilterName.smudge(ausgelöst am git checkout) und

    git config --global filter.yourFilterName.smudge 'sed "s/isPhoneGap = .*/isPhoneGap = true/"'
    
  • yourFilterName.clean(ausgelöst am git add)

    git config --global filter.yourFilterName.clean 'sed "s/isPhoneGap = .*/isPhoneGap = false/"'
    

Ihre Datei würde unverändert angezeigt git status, die ausgecheckte Version hätte jedoch den richtigen Wert für isPhoneGap.

VonC
quelle
1
Danke dafür. habe es zum Laufen gebracht. Wissen Sie, wie man einen git diff or Git-Status erstellt? Ignorieren Sie die Filter? So kann ich immer noch sehen, was anders ist? Mein Anwendungsfall ist für Debug-Protokolle ... die ich schließlich löschen möchte ... @jthill @VonC
timh
1
@timh Wenn der Filter funktioniert, sollte der Git-Status oder der Git-Diff nichts anzeigen.
VonC
1
Schade, dass es in GIT keinen einfacheren Weg gibt. git ignore <Dateiname> <Leinennummer> wäre so praktisch!
Kiedysktos
22
@kiedysktos Leinenzahl? Was ist, wenn sich die Zeilennummer ändert?
VonC
Dies hat gut funktioniert, aber Windows-Benutzer sollten aufpassen, dass die gitconfig sehr wählerisch ist, mit welchen Zeichen sie gespeichert werden soll. Wenn Sie also einige semi-exotische reguläre Ausdrücke ausprobieren, können Probleme auftreten. Am Ende habe ich meine sed-Aufrufe in eine separate helper.sh-Datei gestellt, die ich von meiner gitconfig aufgerufen habe sh ".git/helper.sh", um sicherzustellen, dass alle Parameter durchlaufen werden, mit denen sed ausgeführt werden soll "$@"(ich gehe davon aus, dass nur der Dateipfad übergeben wird).
Ohaal
43

Sie können verwenden

git update-index --assume-unchanged [file]

um die Änderungen einer Datei zu ignorieren, die Sie nicht verfolgen möchten. Ich verwende diese Lösung, wenn ich eine Datei im Repository haben muss, aber diese Datei enthält einige Teile, die sich ändern und die ich nicht immer verfolgen muss.

Wenn die Datei wichtige Änderungen enthält, müssen Sie Folgendes tun:

git update-index --no-assume-unchanged [file]

Siehe auch den Git doc update-index für --[no-]assume-unchangedParameter.

Wenn diese Flags angegeben werden, werden die für die Pfade aufgezeichneten Objektnamen nicht aktualisiert. Stattdessen setzen und deaktivieren diese Optionen das Bit "Unverändert annehmen" für die Pfade. Wenn das Bit "Unverändert annehmen" aktiviert ist, überprüft git die Arbeitsbaumdateien nicht mehr auf mögliche Änderungen. Sie müssen das Bit daher manuell deaktivieren, um git mitzuteilen, wenn Sie die Arbeitsbaumdatei ändern.

Carlos
quelle
2
Wird dadurch immer noch die neue Version abgerufen, wenn ich Git Pull mache?
Saad Rehman Shah
1
@Caffeine Wenn Sie Git Pull ausführen, erhalten Sie die letzte Version, die festgeschrieben wurde. Dies ist die letzte, bevor Sie die Datei in "--assume-unverändert" ändern.
Carlos
1
Ich glaube, dass dies --skip-worktreefür die meisten Zwecke eine bessere Option ist. stackoverflow.com/a/39583010/4233593
Jeff Puckett
3
Dies ignoriert Aktualisierungen der gesamten Datei, nicht einer bestimmten Zeile
Nikoss
6

Mit Gitx sollten Sie einzelne Zeilen festschreiben oder ignorieren können (das wissen Sie vielleicht schon), aber Sie müssten dies jedes Mal tun, wenn Sie festschreiben. Ich denke, es wäre besser, eine Konfigurationsdatei pro Bereitstellungsziel (Sie können diese versionieren) und einige Laufzeitparameter zu haben, unabhängig davon, wie Sie den Server starten (wie ./myserver --config=whatever.js).

Andy Ray
quelle
5

Fortsetzung https://stackoverflow.com/a/20574486/4935114 , @ Mike vorgeschlagen , eine schaffen pre-commitHaken, wird grepdie inszenierte Dateien für die Leitungen in die man ignorieren könnte wollen. Der Hook prüft, ob diese Zeilen inszeniert wurden. Wenn ja, ist es eine echoWarnung und es ist exitmit Code, 1so dass der Festschreibungsprozess nicht fortgesetzt wird.

Inspiriert von @ Mikes Antwort fand ich mich darin wieder, eine verbesserte Version seines Hakens zu verwenden, die automatisch reset (mit der -pFlagge) der spezifischen Zeile entspricht, die wir ignorieren möchten.

Ich bin nicht sicher, ob dieser Hook in einer Situation funktioniert, in der viele Dateien mit dieser Zeile ignoriert werden müssen, aber dieser pre-commitHook sucht nach einer Änderung in dieser Zeile in einer bestimmten Datei buildVars.java. Das Hook-Skript sah so aus, als ich es auf meinem Computer testete.

#!/bin/sh

# this hook looks for lines with the text `var isPhoneGap = false;` in the file `buildVars.java` and it resets these lines to the previous state before staged with `reset -p`

if [[ $(git diff --no-ext-diff --cached buildVars.java | grep --count -e "var\ isPhoneGap[\ ]*=[\ ]*") -ne 0 ]]; then
    cat <<EOW
WARNING: You are attempting to commit changes which are not supposed to be commited according to this \`pre-commit\` hook
This \`pre-commit\` hook will reset all the files containing this line to it's previous state in the last commit.
EOW
    echo /$'\n'isPhoneGap$'\n'y$'\n'q | git reset -p
    # BONUS: Check if after reseting, there is no actual changes to be commited and if so, exit 1 so the commit process will abort.
    if [[ $(git diff --no-ext-diff --cached | wc -l) -eq 0 ]]; then
        echo there are no actual changes to be commited and besides the change to the variable \'isPhoneGap\' so I won\'t commit.
        exit 1
    fi
fi

Erläuterung

Ich habe eine Kontrollsequenz wiederholt, die isPhoneGapwährend eines interaktiven resetProzesses nach dem regulären Ausdruck sucht . Wenn Sie also einen Benutzer emulieren, der drückt, um /zu suchen isPhoneGap, drückt yer, wenn er gefragt wird, ob er diesen Patch verwerfen möchte, und drückt schließlich q, um das Interaktive zu beenden reset.

Der interaktive umgekehrte Patch-Prozess ist hier dokumentiert: https://git-scm.com/docs/git-add#git-add-patch


HINWEIS: Das obige Skript setzt voraus, dass die Variable interactive.singleKeyist false. Wenn Sie Ihre konfiguriert haben true, entfernen Sie alle direkt nach der Warnung $'\n'aus dem echoBefehl.

Doron Behar
quelle
3

So können Sie es mit Git-Filtern machen :

  1. Gitattributes-Datei erstellen / öffnen:
    • <Projektstamm> /. gitattributes (wird in das Repo übernommen)
      ODER
    • <Projektstamm> /. git / info / Attribute (wird nicht in Repo übernommen)
  2. Fügen Sie eine Zeile hinzu, in der die zu filternden Dateien definiert sind:
    • *.rb filter=gitignore, dh Filter ausführen, der gitignorefür alle *.rbDateien benannt ist
  3. Definieren Sie den gitignoreFilter in Ihrem gitconfig:
    • $ git config --global filter.gitignore.clean "sed '/#gitignore$/'d"dh diese Zeilen löschen
    • $ git config --global filter.gitignore.smudge cat, dh nichts tun, wenn Sie eine Datei aus dem Repo ziehen

Anmerkungen:
Dies gilt natürlich für Ruby-Dateien, die angewendet werden, wenn eine Zeile mit endet #gitignoreund global in angewendet werden ~/.gitconfig. Ändern Sie dies, wie Sie es für Ihre Zwecke benötigen.

Warnung!!
Dadurch unterscheidet sich Ihre Arbeitsdatei (natürlich) vom Repo. Jedes Auschecken oder Umbasieren bedeutet, dass diese Zeilen verloren gehen! Dieser Trick mag nutzlos erscheinen, da diese Zeilen beim Auschecken, erneuten Basieren oder Ziehen wiederholt verloren gehen, aber ich habe einen bestimmten Anwendungsfall, um ihn zu nutzen.

Nur git stash save "proj1-debug" während der Filter inaktiv ist (nur vorübergehend deaktivieren gitconfigoder so). Auf diese Weise kann mein Debug-Code jederzeit git stash applyin meinen Code übernommen werden, ohne befürchten zu müssen, dass diese Zeilen jemals versehentlich festgeschrieben werden.

Ich habe eine mögliche Idee, um mit diesen Problemen umzugehen, aber ich werde versuchen, sie ein anderes Mal zu implementieren.

Vielen Dank an Rudi und jw013 für die Erwähnung von Git-Filtern und Gitattributen.

Kache
quelle
2

Ein Inhaltsfiltertreiber ist keine gute Lösung. Möglicherweise können Sie diese Zeile vor git status/ etc ausblenden , sie wird jedoch nicht wirklich ignoriert. Sobald Sie den Wert ändern, wird Ihr Arbeitsverzeichnis als verschmutzt markiert, obwohl die Änderung möglicherweise nicht sichtbar ist.

Wenn Sie wirklich möchten, dass diese Zeile nicht mehr in der Versionskontrolle enthalten ist, ist es möglicherweise das einzig praktikable Mittel, sie in ein Befehlszeilenargument zu ändern oder sie in einer ignorierten Include- oder Build-Datei zu platzieren.

patricktokeeffe
quelle
"Sobald Sie den Wert ändern, wird Ihr Arbeitsverzeichnis als fehlerhaft markiert, obwohl die Änderung möglicherweise nicht sichtbar ist": Dies sollte nicht der Fall sein, wenn das saubere Skript die Datei weiterhin in ihrem ursprünglichen Inhalt wiederherstellt.
VonC
Das hatte ich mir gedacht. Ich verwende GitExtensions und es wird die Datei als geändert angezeigt, obwohl der Diff-Bereich leer ist. Möglicherweise, weil der saubere Filter erst beim Einchecken der Datei ausgeführt wird. Möglicherweise, weil es msysgit ist, nicht git-git. IDK, YMMV
patricktokeeffe
1

Ich vermute, dies könnte etwas sein, das in mehr als einer Zeile Ihrer Quelle auftaucht.

Ich denke, es wäre am saubersten, eine .userbuildconfig-Datei zu haben, die Sie gerade einschließen und die Standardeinstellungen einchecken lassen. Dann können Sie Carlos 'Vorschlag verwenden , um diese Datei allein als unverändert zu markieren. Auf diese Weise werden andere Änderungen an der Datei, in der Sie die Einstellung überprüfen müssen, nicht übersehen.

Auf diese Weise können Sie Präprozessor-Makros lokal optimieren (oder für Java etwa https://stackoverflow.com/a/1813873/1270965 ).

johnb003
quelle
-1

Nee. Sie können nur einzelne Dateien (und mehr) ignorieren, da die Zeilen in .gitignore mit Dateinamen und nicht mit Dateiinhalten übereinstimmen. Sie haben die Lösung hierfür bereits erwähnt, dh ignorieren Sie eine einzelne Datei, die den Inhalt enthält, den Sie ignorieren möchten.

ralphtheninja
quelle
Ich stimme zu, in meinem Fall war es ausreichend und möglich, diesen Inhalt einfach aus einer ignorierten Datei aufzunehmen. Verschieben Sie also alle ignorierbaren Einstellungen. Dort. Außerdem habe ich eine Kopie dieser ignorierten Datei erstellt und sie als Referenz zum Index hinzugefügt, damit die Informationen darüber, was in dieser Datei enthalten sein soll, nicht verloren gehen.
Urs