2012-08-25 13 views
5

Con la última versión de Debian de git (estoy usando 1.7.2.5), he notado que un archivo .git/index puede cambiar misteriosamente, sin que haya realizado ninguna operación que creo que debería cambiar el repositorio. (Mi shell ocasionalmente ejecuta git branch para que pueda mostrar qué rama está desprotegida, pero eso no debería cambiar nada). El cambio da como resultado un archivo .git/index con la misma longitud que el original, pero que contiene diferentes bits. ¿Qué causa este cambio y cómo puedo detenerlo?¿Por qué `.git/index` cambia cuando no he hecho nada en mi repositorio?

(El cambio es inconveniente porque se mete las cosas para el sincronizador Unison archivo.)

+3

El índice se actualiza con información estadística cada vez que un archivo en el directorio de trabajo es inspeccionado por git. Hace que las operaciones posteriores sean más rápidas porque git puede omitir la inspección del contenido de un archivo en muchos casos si no se ha actualizado desde la última operación de git. ¿No puedes excluir tu directorio .git de la sincronización de archivos? –

+0

¿Por qué estás usando 'unison' para sincronizar tu git repo? Eso es un poco extraño. Solo usa 'git' directamente. –

+2

@KevinBallard Estoy usando el unísono para sincronizar un directorio de inicio que contiene cientos de miles de archivos y muchos gigabytes, así como varias docenas de repositorios de git. La mayoría de estos repositorios git no tienen otras réplicas. –

Respuesta

3

El archivo de índice no sólo debe cambiar aleatoriamente. Ese es el árbol de etapas, un buffer entre el repositorio de commits y el árbol de trabajo. Para mayor eficiencia, también almacena algunos metadatos sobre el árbol de trabajo (los archivos desprotegidos que puede modificar), que permitirían resultados más rápidos status o diff. Para ver qué tipo de información se almacena, intente ejecutar git ls-files --debug. Esto debería imprimir, para cada archivo y directorio, algo así como:

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

lo tanto, si un archivo cambia de ninguna manera en el disco, no como su contenido, pero cosas internas como la que INODE que está usando, se disparará una actualización del archivo index la próxima vez que se use el índice.

git branch no actualiza el índice, ya que sólo se comprueba el archivo .git/HEAD y los archivos .git/refs/heads y .git/packed-refs, que no se preocupa por el índice o el árbol de trabajo. git diff y git status, por otro lado, funcionan con el índice.

Hice un experimento: copié el archivo actual index, creé una nueva versión de un archivo asegurándome de que se le asignaría un nuevo inodo (copiar, eliminar el original, cambiar el nombre de la copia al nombre original) , ejecutó git status, y luego comparó el nuevo archivo de índice con la copia original. Dos cosas cambiaron: una línea que contenía el archivo afectado, y los cambios estaban en los bytes justo antes del nombre de archivo, y algunos bytes justo al final del archivo de índice, probablemente una marca de tiempo para el último cálculo de índice. El tamaño total del archivo sigue siendo el mismo.

Volver a su problema, si no está ejecutando ningún comando que toque el índice usted mismo, entonces tal vez tenga otra herramienta para usted: un complemento IDE o una extensión de navegador de archivos que conoce repositorios git, y que verifica el estado de los repositorios de git. O bien, hay otro proceso que cambia la forma en que se almacenan los archivos en el disco, como una utilidad de desfragmentación de disco.

+2

El índice de Git (el contenido lógico) puede no cambiar cuando lo haces (por ejemplo) 'git status' pero el archivo de índice en sí mismo (' .git/index') a menudo lo hará y esto es lo que realmente pregunta la pregunta. –

+0

¿Por qué cambiaría?Cuando dice que _el archivo de índice a menudo cambiará _, ¿lo dice basándose en el conocimiento, o es solo una suposición basada en los síntomas informados por el OP? –

+1

git actualizará la información en caché en '.git/index' si está realizando una operación que inspecciona el árbol de trabajo y encuentra que la información en caché está desactualizada. Esto podría suceder con 'git status',' git diff', 'git grep', etc. –

3

Me he encontrado con este problema también, y creo que es la interacción entre unison y git la que está causando el problema. Cuando unison sincroniza los dos directorios, no sincroniza los ctimes. Eso significa que en una copia del repositorio de git, digamos copy 2, el archivo c veces no coincide con los tiempos almacenados en .git/index. Eso significa que .git/index en la copia 2 se actualizará la próxima vez que ejecute un comando git de los archivos de estadísticas. Cuando se ejecuta unison, .git/index se copia para copiar 1, pero luego su contenido no coincide con el ctimes allí. Entonces, la próxima vez que se ejecute un comando git allí, el índice se actualizará. Luego, unison lo copia para copiar 2, etc.

No he encontrado una solución razonable para esto. Establecer core.trustctime = false no ayuda.

En la medida en que .git/index es un caché, se debe omitir de la sincronización al unísono. Pero yo creo eso.git/index también se usa para organizar archivos, y uno puede comenzar ese proceso en una máquina y terminarlo en otra, lo que requeriría que se sincronice .git/index.

(Sé que algunas personas piensan que es extraño sincronizar repositorios git al unísono, pero el punto de armonía es que puedes cambiar entre trabajar en dos máquinas diferentes y continuar exactamente donde lo dejaste. ¡Es una herramienta increíble!)

+0

No creo que sea porque "no sincroniza" las veces y mtimes, sospecho que es * que * sincroniza los mtimes. Y el tiempo en una máquina no va a ser el tiempo en otra. (Además, es posible que Unison aumente las veces y las mtimes en su workdir). –

+1

@EdwardThomson: Unison sincroniza los mtimes (no hasta el presente, sino para coincidir con el tiempo en la otra copia), pero eso no es suficiente para mantener a git feliz, ya que actualiza .git/index aunque solo cambien las veces. Unison no cambia las horas a menos que cambie algo más sobre un archivo, pero no (y realmente no puede) * sincronizar * las veces. Por lo tanto, el ciclo anterior ocurre sin * ningún * cambio en las veces y los minutos de los archivos en el repositorio de git. Sucede porque el archivo .git/index sigue cambiándose entre almacenar las copias de una copia y las veces de la otra copia. –

+0

Ah sí, eso tiene sentido, ¿no? Creo que esto sugiere que no deberías usar Unison para sincronizar un repositorio no simple, pero esa es solo mi opinión. –

0

Probablemente esta no sea la solución para el autor de esta pregunta, pero en mi caso la función autocommit de diario de etckeeper fue la culpable.

+0

Gracias, pero estoy viendo este problema en otros repositorios git, no en '/ etc'. –

0

Veo el mismo problema en una configuración en la que tengo Unison sincronizando mi directorio de inicio (contiene 3 repositorios de git) entre 2 máquinas, así como un trabajo cron que se almacena en cada directorio de repositorio y ejecuta un 'estado de git' todos los días (y me envía un correo electrónico si los cambios no están marcados). Mi prueba indica que es causada por el hecho de que .git/index almacena datos específicos de la máquina como el número de inodo de los archivos [1].

Para probar esto, tome un repositorio que ya esté sincronizado e idéntico en las 2 máquinas. Copie el .git/index de una máquina a la otra, p. scp -p machineB:/home/me/myrepo/.git/index /home/me/myrepo/.git/index

Ahora comparar los dos archivos y debería ver que son idénticos: sha1sum /home/me/myrepo/.git/index ssh machineB "sha1sum /home/me/myrepo/.git/index"

Ahora ejecute: git status

Ahora compare los 2 archivos de nuevo y usted encontrará que ha cambiado: sha1sum /home/me/myrepo/.git/index ssh machineB "sha1sum /home/me/myrepo/.git/index"

No veo una solución para esto, ya que no puedes usar git sin ejecutar comandos como el estado de git que actualiza el índice.

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

Cuestiones relacionadas