2012-08-25 6 views
5

Mit der neuesten Debian-Version von git (ich benutze 1.7.2.5), habe ich festgestellt, dass eine .git/index Datei auf mysteriöse Weise ändern kann, ohne dass ich irgendeine Operation ausgeführt habe, die das Repository ändern sollte. (Meine Shell läuft gelegentlich git branch, so dass es anzeigen kann, welcher Zweig ausgecheckt ist, aber das sollte nichts ändern.) Die Änderung führt zu einer .git/index Datei mit der gleichen Länge wie das Original, aber enthält verschiedene Bits. Was verursacht diese Änderung und wie kann ich sie stoppen?Warum ändert sich `.git/index`, wenn ich nichts an meinem Repository vorgenommen habe?

(Die Veränderung ist unbequem, weil es die Dinge für die Unison File Synchronizer verunstaltet.)

+3

Der Index mit Stat-Informationen jedes Mal, wenn eine Datei im Arbeitsverzeichnis von git inspiziert aktualisiert wird. Es macht nachfolgende Operationen schneller, da Git den Inhalt einer Datei in vielen Fällen überspringen kann, wenn es seit der letzten Git-Operation nicht aktualisiert wurde. Können Sie Ihr .git-Verzeichnis nicht von der Dateisynchronisierung ausschließen? –

+0

Warum verwenden Sie "Unisono", um Ihr Git Repo zu synchronisieren? Das ist irgendwie komisch. Verwenden Sie einfach 'git' direkt. –

+2

@KevinBallard Ich verwende Unison, um ein Home-Verzeichnis zu synchronisieren, das Hunderttausende von Dateien und viele Gigabytes sowie einige Dutzend Git-Repos enthält. Die meisten dieser Git Repos haben keine anderen Repliken. –

Antwort

3

Die Indexdatei ändern, nur zufällig nicht sollte. Das ist der Zwischenspeicher, ein Puffer zwischen dem Repository von Commits und dem Arbeitsbaum. Für die Effizienz speichert es auch einige Metadaten über den funktionierenden Baum (die ausgecheckten Dateien, die Sie ändern können), die schnellere status oder diff Ergebnisse ermöglichen würden. Um zu sehen, welche Art von Informationen gespeichert sind, versuchen Sie git ls-files --debug auszuführen. Dies sollte drucken, für jede Datei und Verzeichnis, so etwas wie:

path/to/file 
    ctime: 1332898839:873326227 
    mtime: 1332898839:873326227 
    dev: 2052  ino: 4356685 
    uid: 1000  gid: 100 
    size: 3065 flags: 6c 

Also, wenn eine Datei ändert in keiner Weise auf der Platte, nicht als Inhalt, sondern interne Sachen wie dem Inode es verwendet wird, wird es auslösen ein Update auf die Datei index, wenn der Index das nächste Mal verwendet wird.

git branch den Index nicht aktualisiert werden, da es die .git/HEAD-Datei und die .git/refs/heads und .git/packed-refs Dateien überprüft nur, es geht um den Index oder der Arbeits Baum kümmert sich nicht darum. git diff und git status, auf der anderen Seite, arbeiten Sie mit dem Index.

Ich habe ein Experiment gemacht: Ich kopierte die aktuelle Datei index, ich erstellte eine neue Version einer Datei, die sicherstellt, dass ihr ein neuer Inode zugewiesen wird (kopiere, entferne Original, benenne die Kopie zurück auf den ursprünglichen Namen) , führte git status aus und verglichen dann die neue Indexdatei mit der ursprünglichen Kopie. Zwei Dinge änderten sich: eine Zeile, die die betroffene Datei enthielt, und die Änderungen waren in den Bytes direkt vor dem Dateinamen und ein paar Bytes direkt am Ende der Indexdatei, wahrscheinlich ein Zeitstempel für die letzte Indexberechnung. Die Gesamtgröße der Datei blieb gleich.

Zurück zu Ihrem Problem, wenn Sie keinen Befehl ausführen, der den Index selbst berührt, dann haben Sie vielleicht ein anderes Werkzeug, das das für Sie tut: ein IDE-Plugin oder eine Datei-Browser-Erweiterung, die Git-Repositories kennt welches den Status von Git-Repositories überprüft. Oder es gibt einen anderen Prozess, der die Art ändert, in der Dateien auf der Festplatte gespeichert werden, z. B. ein Disk-Defrag-Dienstprogramm.

+2

Git Index (der logische Inhalt) kann nicht ändern, wenn Sie (z. B.) git status, aber die Indexdatei selbst ('. Git/index ') wird oft und das ist, worum die Frage wirklich fragt. –

+0

Warum sollte es sich ändern?Wenn Sie sagen, dass _die Indexdatei selbst oft [ändern] _, sagen Sie, dass basierend auf Wissen, oder es ist nur eine Annahme basierend auf den Symptomen von der OP gemeldet? –

+1

git aktualisiert die zwischengespeicherten Informationen in '.git/index', wenn eine Operation ausgeführt wird, die die Arbeitsbaumstruktur überprüft und feststellt, dass die zwischengespeicherten Informationen nicht mehr aktuell sind. Das kann passieren mit 'git status',' git diff', 'git grep', etc. –

3

Ich bin auch auf dieses Problem gestoßen, und ich glaube, es ist die Interaktion zwischen Unison und Git, die das Problem verursacht. Wenn Unison die zwei Verzeichnisse synchronisiert, synchronisiert es die Ctimes nicht. Das bedeutet, dass in einer Kopie des Git-Repositorys, z. B. Kopie 2, die Datei-Ctimes nicht mit den in .git/index gespeicherten Zeiten übereinstimmen. Das bedeutet, dass .git/index in Kopie 2 aktualisiert wird, wenn Sie das nächste Mal einen Git-Befehl ausführen, der Dateien stats ausführt. Wenn Unison ausgeführt wird, wird .git/index auf Kopie 1 kopiert, aber sein Inhalt stimmt nicht mit den Ctimes dort überein. Wenn also ein git-Befehl das nächste Mal ausgeführt wird, wird der Index aktualisiert. Dann kopiert Unison es zu Kopie 2, usw.

Ich habe keine vernünftige Abhilfe dafür gefunden. Die Einstellung core.trustctime = false hilft nicht.

In dem Maße, in dem .git/index ein Cache ist, sollte es aus der Synchronisation durch Unisono weggelassen werden. Aber ich glaube das.git/index wird auch verwendet, um Dateien zu staffeln, und man könnte diesen Prozess auf einem Computer starten und auf einem anderen beenden, was erfordert, dass .git/index synchronisiert wird.

(Ich weiß, einige Leute denken, es ist seltsam, Git Repos mit Unison zu synchronisieren, aber der Punkt der Unisono ist, dass Sie zwischen zwei verschiedenen Maschinen arbeiten und genau dort fortsetzen können, wo Sie aufgehört haben. Es ist ein erstaunliches Werkzeug!)

+0

Ich glaube nicht, dass es die Ctimes und Mtimes nicht "synchronisiert", ich vermute, dass es die Mtimes synchronisiert. Und die Zeit auf einer Maschine wird nicht die Zeit auf einer anderen sein. (Plus, Unison selbst erhöht wahrscheinlich die Ctimes und Mtimes in Ihrem Workdir.) –

+1

@EdwardThomson: Unison synchronisiert die Mtimes (nicht mit der Gegenwart, sondern mit der Zeit in der anderen Kopie), aber das ist nicht genug, um git zu halten glücklich, wie es aktualisiert .git/index auch wenn nur die ctimes ändern. Unison ändert die Ctimes nicht selbst, es sei denn, es ändert etwas an einer Datei, aber es synchronisiert die Ctimes nicht (und kann es wirklich nicht) *. Die obige Schleife passiert also ohne * irgendwelche * Änderungen an den Ctimes und Mtimes der Dateien im Git Repo. Dies geschieht, weil die .git/index-Datei zwischen dem Speichern der Ctimes von einer Kopie und den Ctimes von der anderen Kopie wechselt. –

+0

Ah ja, das macht Sinn, nicht wahr? Ich würde denken, dass dies darauf hindeutet, dass Sie nicht Unison verwenden sollten, um ein nicht-bare-Repository zu synchronisieren, aber das ist nur meine Meinung. –

0

Dies wird wahrscheinlich nicht die Lösung für den Autor dieser Frage sein, aber in meinem Fall war die tägliche Autocommit-Funktion von Etckeeper der Schuldige.

+0

Danke, aber ich sehe dieses Problem in anderen Git-Repositories, nicht in '/ etc'. –

0

Ich sehe das gleiche Problem auf einem Setup, wo ich Unison mein Home-Verzeichnis (mit 3 Git-Repos) zwischen zwei Maschinen, sowie einen Cron-Job, dass CD in jedem Repo-Verzeichnis und einen 'Git-Status' jeden Tag läuft (und sendet mir eine E-Mail, wenn Änderungen nicht eingecheckt sind). Meine Tests weisen darauf hin, dass dies auf die Tatsache zurückzuführen ist, dass .git/index maschinenspezifische Daten wie die Inode-Anzahl von Dateien speichert [1].

Um dies zu testen, nehmen Sie ein Repo, das bereits synchronisiert und identisch auf den 2 Maschinen ist. Kopieren Sie den .git/Index von einer Maschine zur anderen, z. scp -p machineB:/home/me/myrepo/.git/index /home/me/myrepo/.git/index

nun die beiden Dateien vergleichen und Sie sollten sie sind identisch sehen: sha1sum /home/me/myrepo/.git/index ssh machineB "sha1sum /home/me/myrepo/.git/index"

Jetzt laufen: git status

nun die 2-Dateien wieder vergleichen, und Sie finden sie geändert haben:

Ich sehe keine Lösung für diese, da Sie Git nicht verwenden können, ohne Befehle wie Git-Status ausführen, die den Index aktualisieren.

[1] https://github.com/git/git/blob/867b1c1bf68363bcfd17667d6d4b9031fa6a1300/Documentation/technical/index-format.txt#L38

Verwandte Themen