¿Cómo 'git pull' se comió mi tarea?

53

Me siento como un niño en la oficina del director explicando que el perro se comió mi tarea la noche antes de la fecha de vencimiento, pero estoy mirando un error de pérdida de datos en la cara y no puedo entender cómo sucedió. ¡Me gustaría saber cómo git podría comer todo mi repositorio! He puesto git a través del escurridor muchas veces y nunca parpadea. Lo usé para dividir un repositorio de 20 Gig Subversion en 27 repositorios de git y filté el foo fuera de ellos para desenredar el desastre y nunca me perdió un byte. El reflog siempre está ahí para recurrir. ¡Esta vez la alfombra se ha ido!

Desde mi punto de vista, todo lo que hice fue ejecutar git pully destruyó todo mi repositorio local. No quiero decir que "estropeó la versión extraída" o "la rama en la que estaba" ni nada de eso. Quiero decir que todo se fue .

Aquí hay una captura de pantalla de mi terminal en el incidente:

captura de pantalla del incidente

Déjame guiarte a través de eso. Mi símbolo del sistema incluye datos sobre el repositorio git actual (usando la implementación vcs_info de prezto) para que pueda ver cuándo desapareció el repositorio git. El primer comando es lo suficientemente normal:

  » caleb » jaguar » ~/p/w/incil.info » ◼  zend ★ »
❯❯❯ git co master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.

Allí puedes ver que estaba en la rama 'zend', y comprobé el maestro. Hasta aquí todo bien. Verá en el indicador antes de mi próximo comando que cambió de rama con éxito:

  » caleb » jaguar » ~/p/w/incil.info » ◼  master ★ »
❯❯❯ git pull
remote: Counting objects: 37, done.
remote: Compressing objects: 100% (37/37), done.
remote: Total 37 (delta 25), reused 0 (delta 0)
Unpacking objects: 100% (37/37), done.
From gitlab.alerque.com:ipk/incil.info
 + 7412a21...eca4d26 master     -> origin/master  (forced update)
   f03fa5d..c8ea00b  devel      -> origin/devel
 + 2af282c...009b8ec verse-spinner -> origin/verse-spinner  (forced update)
First, rewinding head to replay your work on top of it...
>>> elapsed time 11s

Y así como así se fue. El marcador de tiempo transcurrido sale antes del siguiente mensaje si han transcurrido más de 10 segundos. Git no dio ningún resultado más allá del aviso de que se estaba rebobinando para reproducir. No hay indicios de que haya terminado.

El siguiente mensaje no incluye datos sobre en qué rama estamos o el estado de git.

Sin darme cuenta de que había fallado, intenté ejecutar inconscientemente otro comando git solo para decirme que no estaba en un repositorio git. Tenga en cuenta que el PWD no ha cambiado:

  » caleb » jaguar » ~/p/w/incil.info »
❯❯❯ git fetch --all
fatal: Not a git repository (or any parent up to mount point /home)
Stopping at filesystem boundary (GIT_DISCOVERY_ACROSS_FILESYSTEM not set).

Después de esto, un vistazo mostró que estaba en un directorio completamente vacío. Nada. No hay directorio '.git', nada. Vacío.

Mi git local está en la versión 2.0.2. Aquí hay un par de cositas de mi configuración de git que podrían ser relevantes para entender lo que sucedió:

[branch]
        autosetuprebase = always
        rebase = preserve
[pull]
        rebase = true
[rebase]
        autosquash = true
        autostash = true
[alias]
        co = checkout

Por ejemplo, he git pullconfigurado hacer siempre un rebase en lugar de una fusión, de modo que parte de la salida anterior sea normal.

Puedo recuperar los datos. No creo que haya ningún objeto git que no sea un alijo sin importancia que no haya sido empujado a otros repositorios, pero me gustaría saber qué sucedió .

He verificado por:

  • Mensajes en dmesg o el diario systemd. Nada ni remotamente relevante.
  • No hay indicios de falla de la unidad o del sistema de archivos (LVM + LUKS + EXT4 parecen normales). No hay nada en perdido + encontrado.
  • No corrí nada más. No hay nada en la historia que no esté mostrando arriba, y no se usaron otras terminales durante este tiempo. No hay rmcomandos flotando que puedan haberse ejecutado en el CWD incorrecto, etc.
  • Poking en otro repositorio de git en otro directorio no muestra ninguna anormalidad aparente en la ejecución de git pulls.

¿Qué más debería estar buscando aquí?

Caleb
fuente
44
@Patrick Como ya expliqué en la pregunta, .gitno no existe. Nada funciona: lo que solía ser el directorio raíz de git no tiene nada en absoluto.
Caleb
2
@Alexander La operación de extracción es normal (aparte de ser un rebase en lugar de una fusión). El aviso sobre una actualización forzada indica que el repositorio del que estoy obteniendo un impulso forzado lo restableció desde una posición diferente a la del último repositorio local. Esto es normal porque estoy sincronizando material desarrollado activamente y con frecuencia rebase entre mis propias computadoras, no una rama pública que verán otros desarrolladores.
Caleb
3
@Caleb su indicador de shell incluye indicación de rama git, lo que significa que la formación de PS1 incluye comandos git que no están expuestos en su registro. Principalmente pueden cambiar la imagen y pueden ser la fuente del problema. Debe actualizar la pregunta que describe con precisión cómo se forma su solicitud de shell, qué comandos se ejecutan para obtener una rama actual y reconsiderar cómo podrían estropear su repositorio.
Netch
2
@Caleb Realmente deberías preguntar en la lista de correo de desarrollo de git; Puede escribirlo como un informe de error, o simplemente preguntar de manera informal: de todos modos, es lo mismo. Hay algunos desarrolladores que conocen git de manera impresionante, probablemente puedan decir por intuición lo que podría haber sucedido. (Si no, simplemente seguirán la discusión en silencio.) Y saben si sucedió antes. (Informando que existe la forma "oficial" de informar errores para git)
Volker Siegel
77
@Wildcard En realidad, he tenido la intención de armar una respuesta a esto, ya que realmente descubrí lo que sucedió. El sistema había salido recientemente de la suspensión y la red había estado apagada durante días antes de que se fuera a dormir. En algún lugar de ese proceso, dejé un proceso pacman en ejecución que intentaba actualizar algo en el sistema. En resumen, resulta que glibc se actualizó y el binario git se sobrescribió. Debido a la forma en que se bifurcó, una instancia terminó siendo diferente a la otra y se almorzaron mutuamente. El directorio realmente estaba vacío (no solo apareció
Caleb

Respuestas:

6

Sí, gitcomí mi tarea. Todo ello.

Hice una ddimagen de este disco después del incidente y lo jugué más tarde. Al reconstruir la serie de eventos a partir de los registros del sistema, deduzco que lo que sucedió fue algo como esto:

  1. Se pacman -Syuhabía emitido un comando de actualización del sistema ( ) días antes de este incidente.
  2. Una interrupción prolongada de la red significó que se volvió a intentar descargar paquetes. Frustrado por la falta de internet, puse el sistema a dormir y me fui a la cama.
  3. Días después, el sistema se despertó y comenzó a buscar y descargar paquetes nuevamente.
  4. La descarga del paquete terminó en algún momento justo antes de que estuviera jugando con este repositorio.
  5. La instalación del sistema glibc se actualizó después git checkouty antes del git pull.
  6. El gitbinario se reemplazó después del git pullinicio y antes de que terminara.
  7. Y al séptimo día, gitdescansó de todas sus labores. Y borró el mundo para que todos los demás tuvieran que descansar también.

No sé exactamente qué condición de carrera ocurrió que hizo que esto sucediera, pero intercambiar binarios en medio de una operación ciertamente no es agradable ni una condición comprobable / repetible. Por lo general, una copia de un binario en ejecución se almacena en la memoria, pero gites extraño y algo sobre la forma en que vuelve a generar versiones de sí mismo, estoy seguro de que condujo a este desastre. Obviamente debería haber muerto en lugar de destruir todo, pero eso fue lo que sucedió.

Caleb
fuente
1
git podría haber fallado porque git se hace usando diferentes comandos, en lugar de un solo binario. Se ejecuta un simple git pull git-fetch, git-rebaseo git-mergeygit gc
Ferrybig
2

Posiblemente al no definir la ruta del archivo que se va a eliminar.

Su caso me recordó un hermoso día cuando mi remove(path)método casero intentó eliminar la carpeta raíz porque el parámetro dado era una cadena vacía que el sistema operativo corrigió (!) Como la carpeta raíz.

Esto puede ser un error git similar. Tal que:

  1. El comando Rebase quería eliminar un archivo como remove(project_folder + file_path)(pseudocódigo)
  2. De alguna manera file_pathestaba vacío en ese momento.
  3. Comando evaluado como algo así remove(project_folder)
maliayas
fuente
1

Con suerte, puede solucionar esto con el siguiente comando:

git reset --hard ORIG_HEAD  

Cuando comienzan los posibles cambios peligrosos, git oculta su estado actual en ORIG_HEAD. Con él puedes deshacer una fusión o un rebase.

Manual de Git: Deshacer una fusión

Routhinator
fuente
44
No creo que leas toda la pregunta. Este tipo de solución está completamente fuera de discusión porque no hay metadatos git . Hacer un reinicio como este requiere un directorio .git existente y algunos objetos en él para trabajar. No tengo nada. No es solo un directorio de trabajo desordenado, ya no es un repositorio de ningún tipo.
Caleb
Ahh, mis disculpas. Eso es muy inusual. Si git repo se ha ido, supongo que no habrá forma de recuperarse a menos que esté sombreando archivos en Linux y tenga las copias de seguridad fs de los archivos. Eliminaré mi respuesta ya que es irrelevante.
Routhinator
Sí, sé que es un problema inusual (y tengo copias de seguridad). Mi pregunta aquí es cómo salió mal ... dónde buscar el error en git o mi controlador del sistema de archivos o cualquier otra cosa que podría haber molestado para comer un directorio en medio de una operación como esta.
Caleb
También tengo mucha curiosidad. Hatr para que algo como esto le pase a mis repositorios.
Routhinator
-1

Parece que alguien corrió git push --forceen este repositorio, y usted eliminó esos cambios. Intente clonar el repositorio fresco, eso debería volver a ponerlo en un estado de trabajo limpio nuevamente.

conorsch
fuente
1
El empuje forzado rebajó el último puñado de cometidos. Eso no fue lo que eliminé (¡el directorio de trabajo ya no es un directorio de trabajo!) E incluso si fuera una re-clonación no tendría ningún sentido.
Caleb
44
No creo que pueda eliminar el .gitdirectorio de alguien con un empuje forzado
Grzegorz