Git - Unterschied zwischen 'unverändert annehmen' und 'Arbeitsbaum überspringen'

450

Ich habe lokale Änderungen an einer Datei, die ich nicht in mein Repository übertragen möchte. Es ist eine Konfigurationsdatei zum Erstellen der Anwendung auf einem Server, aber ich möchte lokal mit verschiedenen Einstellungen erstellen. Natürlich wird die Datei immer angezeigt, wenn ich 'git status' als etwas inszeniere. Ich möchte diese besondere Änderung verbergen und nicht begehen. Ich werde keine weiteren Änderungen an der Datei vornehmen.

Nach einigem Stöbern sehe ich zwei Optionen: 'unverändert annehmen' und 'Arbeitsbaum überspringen'. Eine frühere Frage hier spricht über sie, erklärt aber nicht wirklich ihre Unterschiede. Meine Frage lautet: Wie unterscheiden sich die beiden Befehle? Warum sollte jemand den einen oder anderen benutzen?

ckb
quelle
1
Normalerweise benutze ich .gitignorefür ähnliche Zwecke. Würde diese Lösung für Sie funktionieren?
Samuil
45
samuil, .gitignore ignoriert das Hinzufügen, nicht das Ändern. Wenn die Datei bereits in Git ist, wird das Ereignis verfolgt, wenn es in .gitignore
Grigory
aber kann man nicht alle entfernen und alle hinzufügen, um wie hier erklärt "zu aktualisieren"? stackoverflow.com/questions/7075923/… @Grigory
Daniel Springer
1
Die Datei sollte nicht ignoriert werden, wenn ich die Absicht von OP richtig verstehe. Die Datei muss sich im Repository befinden, aber diese sehr spezifischen Änderungen, die er vorgenommen hat, sollten nicht festgeschrieben werden - zumindest nicht jetzt.
Simone

Antworten:

666

Du willst skip-worktree.

assume-unchangedwurde für Fälle entwickelt, in denen es teuer ist, zu überprüfen, ob eine Gruppe von Dateien geändert wurde. Wenn Sie das Bit setzen, wird git(natürlich) davon ausgegangen, dass die Dateien, die diesem Teil des Index entsprechen, in der Arbeitskopie nicht geändert wurden. So wird ein Durcheinander von statAnrufen vermieden . Dieses Bit geht verloren, wenn sich der Eintrag der Datei im Index ändert (also wenn die Datei stromaufwärts geändert wird).

skip-worktreeist mehr als das: Selbst wenn bekannt ist git , dass die Datei geändert wurde (oder durch ein reset --hardoder ähnliches geändert werden muss ), wird sie so tun, als ob dies nicht der Fall wäre, und stattdessen die Version aus dem Index verwenden. Dies bleibt so lange bestehen, bis der Index verworfen wird.

Hier finden Sie eine gute Zusammenfassung der Auswirkungen dieses Unterschieds und der typischen Anwendungsfälle: http://fallengamer.livejournal.com/93321.html .

Aus diesem Artikel:

  • --assume-unchangedgeht davon aus, dass ein Entwickler eine Datei nicht ändern sollte . Dieses Flag dient zur Verbesserung der Leistung für nicht ändernde Ordner wie SDKs.
  • --skip-worktreeist nützlich, wenn Sie git anweisen, eine bestimmte Datei niemals zu berühren, da Entwickler sie ändern sollten . Wenn das Upstream-Haupt-Repository beispielsweise einige produktionsbereite Konfigurationsdateien hostet und Sie nicht versehentlich Änderungen an diesen Dateien vornehmen möchten, --skip-worktreeist dies genau das, was Sie möchten.
Borealid
quelle
3
Das macht Sinn. skip-worktree scheint in der Tat der richtige Weg zu sein. Vielen Dank!
ckb
99
Eine kleine Notiz, um ein paar Sekunden beim Suchen und Lesen zu sparen. Um --skip-worktreeEffekte abzubrechen und das Flag zu deaktivieren, gibt es eine --no-skip-worktreeOption. Funktioniert genauso. Dies ist nützlich, wenn eine Hand ausgerutscht ist und falsche Dateien markiert wurden oder wenn sich die Umstände geändert haben und zuvor übersprungene Dateien nicht mehr ignoriert werden sollten.
Drdaeman
18
Um meine eigene Frage oben zu beantworten, besteht der Unterschied zwischen der Verwendung --skip-worktreeund der .git/info/excludeDatei darin, dass die erstere auch für Dateien funktioniert, die derzeit verfolgt werden. .git/info/exclude, Wie .gitignore, nur versehentlich untracked Dateien zum Index hinzugefügt verhindern, aber keine Änderungen an Dateien zu machen , die bereits verfolgt werden.
LinusR
13
Kann dies auf die Fernbedienung übertragen und von allen Klonen beibehalten werden?
CMCDragonkai
4
Nur die Verwendung , Ma'am:git update-index --skip-worktree <file_name>
Ruffin
108

Hinweis: Fallengamer hat 2011 einige Tests durchgeführt (daher sind sie möglicherweise veraltet). Hier sind seine Ergebnisse :

Operationen

  • Die Datei wird sowohl im lokalen Repository als auch im Upstream geändert
    git pull:
    Git behält die lokalen Änderungen trotzdem bei.
    So würden Sie nicht versehentlich Daten verlieren, die Sie mit einem der Flags markiert haben.
    • Datei mit assume-unchangedFlag: Git würde die lokale Datei nicht überschreiben. Stattdessen werden Konflikte ausgegeben und Ratschläge zur Lösung dieser Konflikte gegeben
    • Datei mit skip-worktreeFlag: Git würde die lokale Datei nicht überschreiben. Stattdessen werden Konflikte ausgegeben und Ratschläge zur Lösung dieser Konflikte gegeben

  • Die Datei ist sowohl im lokalen Repository geändert und Upstream, versucht irgendwie zu ziehen Verwendung Ergebnisse in einiger zusätzlichen Handarbeit , aber zumindest würden Sie keine Daten verlieren , wenn Sie alle lokalen Änderungen haben.
    git stash
    git pull
    skip-worktree
    • Datei mit assume-unchangedFlag: Verwirft alle lokalen Änderungen, ohne dass eine Wiederherstellung möglich ist. Der Effekt ist wie ' git reset --hard'. ' git pull' Anruf wird erfolgreich sein
    • Datei mit skip-worktreeFlag: Stash würde bei skip-worktreeDateien nicht funktionieren . ' git pull' schlägt mit dem gleichen Fehler wie oben fehl. Der Entwickler muss das skip-worktreeFlag manuell zurücksetzen , um den Fehler zu speichern und abzuschließen pull.

  • Keine lokalen Änderungen, Upstream-Datei geändert Beide Flags würden Sie nicht daran hindern, Upstream-Änderungen zu erhalten. Git erkennt, dass Sie das Versprechen gebrochen haben , und entscheidet sich dafür, die Realität widerzuspiegeln, indem Sie die Flagge zurücksetzen.
    git pull
    assume-unchanged
    • Datei mit assume-unchangedFlag: Inhalt wird aktualisiert, Flag geht verloren.
      ' git ls-files -v' würde zeigen, dass das Flag in H(von h) geändert wird .
    • Datei mit skip-worktreeFlag: Inhalt wird aktualisiert, Flag bleibt erhalten.
      ' git ls-files -v' würde die gleiche SFlagge wie vor dem zeigen pull.

  • Wenn die lokale Datei geändert wurde, berührt Git die Datei nicht und spiegelt die Realität (die Datei, die versprochen wurde, unverändert zu sein, wurde tatsächlich geändert) für die Datei wider .
    git reset --hard
    skip-worktreeassume-unchanged
    • Datei mit assume-unchangedFlag: Der Dateiinhalt wird zurückgesetzt. Flag wird auf H(von h) zurückgesetzt.
    • Datei mit skip-worktreeFlag: Der Dateiinhalt ist intakt. Flagge bleibt gleich.

Er fügt die folgende Analyse hinzu:

  • Es sieht aus wie skip-worktreeist sehr hart versuchen , Ihre lokalen Daten zu erhalten . Es hindert Sie jedoch nicht daran, vorgelagerte Änderungen vorzunehmen, wenn dies sicher ist. Außerdem setzt git das Flag nicht zurück pull.
    Das Ignorieren des reset --hardBefehls ' ' könnte für einen Entwickler jedoch eine böse Überraschung sein .

  • Assume-unchangedDas Flag könnte bei der pullOperation verloren gehen und die lokalen Änderungen in solchen Dateien scheinen für Git nicht wichtig zu sein.

Sehen:

Er kommt zu dem Schluss:

Eigentlich ist keine der Flags intuitiv genug .

  • assume-unchangedgeht davon aus, dass ein Entwickler eine Datei nicht ändern sollte. Wenn eine Datei geändert wurde, ist diese Änderung nicht wichtig. Dieses Flag dient zur Verbesserung der Leistung für nicht ändernde Ordner wie SDKs.
    Aber wenn das Versprechen gebrochen wird und eine Datei tatsächlich geändert wird, setzt git die Flagge zurück, um die Realität widerzuspiegeln. Wahrscheinlich ist es in Ordnung, einige inkonsistente Flags in Ordnern zu haben, die im Allgemeinen nicht geändert werden sollen.

  • Auf der anderen Seite skip-worktreeist es nützlich, wenn Sie git anweisen, niemals eine bestimmte Datei zu berühren. Dies ist nützlich für eine bereits verfolgte Konfigurationsdatei.
    Das Upstream-Hauptrepository enthält einige produktionsbereite Konfigurationen, Sie möchten jedoch einige Einstellungen in der Konfiguration ändern, um lokale Tests durchführen zu können. Und Sie möchten nicht versehentlich die Änderungen in einer solchen Datei überprüfen, um die Produktionskonfiguration zu beeinflussen. In diesem Fall skip-worktreemacht perfekte Szene.


Mit Git 2.25.1 (Februar 2020) wird das oben erwähnte "Eigentlich ist keines der Flags intuitiv genug" weiter verdeutlicht:

Siehe Commit 7a2dc95 , Commit 1b13e90 (22. Januar 2020) von Brian M. Carlson ( bk2204) .
(Zusammengeführt von Junio ​​C Hamano - gitster- in Commit 53a8329 , 30. Januar 2020)
( Git-Mailingliste )

doc: Benutzer davon abhalten, verfolgte Dateien zu ignorieren

Abgemeldet von: Jeff King
Abgemeldet von: brian m. Carlson

Es ist durchaus üblich, dass Benutzer die Änderungen an einer Datei, die Git verfolgt, ignorieren möchten.

Häufige Szenarien für diesen Fall sind IDE-Einstellungen und Konfigurationsdateien, die im Allgemeinen nicht nachverfolgt und möglicherweise mithilfe eines Vorlagenmechanismus aus nachverfolgten Dateien generiert werden sollten.

Benutzer lernen jedoch die Bits "Annahme unverändert" und "Arbeitsbaum überspringen" kennen und versuchen, sie trotzdem zu verwenden.

Dies ist problematisch, da sich viele Operationen beim Setzen dieser Bits wie vom Benutzer erwartet verhalten, aber normalerweise nicht helfen, wenn git checkouteine Datei ersetzt werden muss.

In diesem Fall gibt es kein vernünftiges Verhalten, da die Daten manchmal wertvoll sind, z. B. bestimmte Konfigurationsdateien, und manchmal irrelevante Daten, die der Benutzer gerne verwerfen würde.

Da dies keine unterstützte Konfiguration ist und Benutzer dazu neigen, die vorhandenen Funktionen für unbeabsichtigte Zwecke zu missbrauchen, was zu allgemeiner Trauer und Verwirrung führt, dokumentieren wir das vorhandene Verhalten und die Fallstricke in der Dokumentation, git update-indexdamit Benutzer wissen, dass sie nach alternativen Lösungen suchen sollten.

Lassen Sie uns außerdem eine empfohlene Lösung für den allgemeinen Fall von Konfigurationsdateien bereitstellen, da bekannte Ansätze in vielen Umgebungen erfolgreich eingesetzt werden.

Die git update-indexManpage enthält jetzt:

Benutzer versuchen häufig, die assume-unchangedund skip-worktree-Bits zu verwenden, um Git anzuweisen, Änderungen an nachverfolgten Dateien zu ignorieren. Dies funktioniert nicht wie erwartet, da Git bei bestimmten Vorgängen möglicherweise weiterhin Arbeitsbaumdateien anhand des Index überprüft. Im Allgemeinen bietet Git keine Möglichkeit, Änderungen an nachverfolgten Dateien zu ignorieren. Daher werden alternative Lösungen empfohlen.

Wenn es sich bei der zu ändernden Datei beispielsweise um eine Art Konfigurationsdatei handelt, kann das Repository eine Beispielkonfigurationsdatei enthalten, die dann in den ignorierten Namen kopiert und geändert werden kann. Das Repository kann sogar ein Skript enthalten, mit dem die Beispieldatei als Vorlage behandelt und automatisch geändert und kopiert wird.

In diesem letzten Teil beschreibe ich einen typischen Inhaltsfiltertreiber, der auf Smudge / Clean-Skripten basiert .

VonC
quelle
7
Wenn Sie einen Skip-Worktree für eine Datei haben und die Upstream-Änderungen vorgenommen wurden, wird beim Abrufen "Bitte festschreiben oder speichern" angezeigt, obwohl der Git-Status die Datei nicht als geändert meldet. Wie können Sie dies vermeiden, damit die lokalen Änderungen bestehen bleiben, während die Leute mit den Produktionseinstellungen am Ursprung herumspielen?
GreenAsJade
3
Ja, das kann ich bestätigen. Es bedeutet, dass es immer noch sehr schwierig ist, eine lokale Datei zu haben, die Sie einfach anders als den Ursprung pflegen möchten.
GreenAsJade
1
@ GreenAsJade als scheint alt. Gibt es eine Chance, dass Sie es mit einem 2.2.x testen können?
VonC
1
@VonC, Der Link zu "Junios Kommentar" befindet sich nicht im Revisionsverlauf. Ist es das, worauf Sie sich bezogen haben?
Michael - Wo ist Clay Shirky
1
@ Michael Guter Fang, danke. Ich habe diesen Link wieder in die Antwort eingefügt.
VonC