A pesar de que GIT NO almacena deltas de archivos, ¿puede revertir a versiones de archivos anteriores (veces ilimitadas?)

14

He leído que Git no almacena deltas de archivos. Si esto es cierto, ¿cómo admite la reversión de archivos a versiones anteriores? Si está almacenando todo el archivo, el espacio del repositorio en el disco debe crecer de manera inmanejable. ¿Git admite reversiones y diferencias de archivos a la versión 1 del archivo? ¿Incluso admite un concepto de versiones relacionado con los archivos? Esto es (creo) esencial para mi comprensión de un VCS / DVCS y mis necesidades. Necesito poder comparar lo que estoy a punto de registrar con versiones anteriores.

Pete Alvin
fuente

Respuestas:

44

Git no arroja información por sí sola *. Todas las versiones anteriores de cada archivo siempre están disponibles para reversiones, diferencias, inspecciones, etc.

Árbol completo versus archivos individuales

Lo que puede estar tratando de conciliar es la idea de acceder a una versión anterior de un archivo individual frente al hecho de que el modelo de historia de Git se centra en todo el árbol. El control de versiones de árbol completo requiere un poco más de trabajo para ver (por ejemplo) la versión foo.ctal como existía hace diez foo.ccambios frente a diez cambios de árbol completo:

# 10 foo.c-changes ago
git show $(git rev-list -n 10 --reverse HEAD -- foo.c | head -1):foo.c

# 10 whole-tree-changes ago
git show HEAD~10:foo.c

Los beneficios de la orientación de árbol, principalmente la capacidad de ver los compromisos como una unidad de cambios interdependientes realizados en varias partes de todo el árbol, en general superan en gran medida el tipeo adicional (que puede aliviarse con alias, scripts, etc.) y el tiempo de CPU pasó cavando a través de compromisos pasados.

Eficiencia de almacenamiento

Cuando un nuevo objeto (por ejemplo, un archivo con contenido no visto previamente) ingresa al sistema, se almacena con compresión simple (zlib) como un "objeto suelto". Cuando se acumulan suficientes objetos sueltos (según la gc.autoopción de configuración; o cuando el usuario ejecuta git gc o uno de los comandos de empaque de nivel inferior), Git recogerá muchos objetos sueltos en un solo "archivo de paquete".

Los objetos en un archivo de paquete se pueden almacenar como datos comprimidos simples (igual que un objeto suelto, simplemente agrupado con otros objetos) o como deltas comprimidos contra algún otro objeto. Los deltas se pueden encadenar a profundidades configurables ( pack.depth) y se pueden hacer contra cualquier objeto adecuado ( pack.windowcontrola qué tan ampliamente Git busca la mejor base delta; una versión de un archivo históricamente no relacionado se puede usar como base si hacerlo produciría un buena compresión delta). La latitud que las configuraciones de profundidad y tamaño de ventana le dan al motor de compresión delta a menudo resulta en una mejor compresión delta que la compresión "diff" simple de una versión contra el siguiente / anterior de estilo CVS.

Es esta compresión delta agresiva (combinada con la compresión zlib normal) lo que a menudo puede permitir que un repositorio de Git (con historial completo y un árbol de trabajo sin comprimir) ocupe menos espacio que un único pago SVN (con un árbol de trabajo sin comprimir y una copia prístina).

Vea las secciones Cómo almacena objetos Git y El paquete de archivos del Libro comunitario de Git . También el git-pack de objetos página de manual .

* Puedes decirle a Git que descarta los commits "reescribiendo el historial" y con comandos como git reset , pero incluso en estos casos Git "se aferra" a los commits recientemente descartados por un tiempo, en caso de que decidas que los necesitas. Ver git reflog y git prune .

Chris Johnsen
fuente
3
+1 solo por la cantidad y el detalle de la información que proporcionó.
Tamara Wijsman
3
Además, debido a que Git usa instantáneas de archivos en lugar de deltas, retroceder mucho en la historia es realmente más fácil. Imagine que necesita ver un archivo de 20 commits hace. Con deltas, debe deshacer 20 conjuntos de cambios; con las instantáneas, solo toma la instantánea correcta. Cuanto más larga sea tu historia, mayor será la ventaja. Y si desea ver la diferencia entre la versión actual y esa, es solo una diferencia, en lugar de tener que decidir qué se ha hecho, deshacer, rehacer, etc.
Nathan Long
Chris, pareces tener un buen manejo de los aspectos internos de Git. ¿Alguna posibilidad de que puedas dar un golpe en esto? stackoverflow.com/questions/5176225/…
Nathan Long
@ChrisJohnsen Por favor, ayúdame a entender esto. Según lo que dijo, ¿puede Git obtener una eficiencia de almacenamiento similar (o mejor) que Subversion? Sé que si confirmo un archivo con pequeños cambios varias veces, se puede guardar 1 GB de datos en 100 MB. ¿Puede Git hacer lo mismo?
Alireza Noori
@AlirezaNoori: Todo depende de la naturaleza de los datos y los cambios capturados (tamaño del archivo, compresibilidad del archivo, tamaño y ubicación de los cambios, etc.). Algo así ciertamente debería ser posible (dependiendo de los detalles). En general, los archivos de paquete de Git pueden extraer de una selección más grande de bases para su compresión delta en comparación con los deltas estrictamente cronológicos inversos que usan los servidores SVN (¿se usa? No sigo el desarrollo SVN ...). Si tiene alguna pregunta específica en mente, debería considerar hacer una nueva pregunta que incluya todos los detalles pertinentes.
Chris Johnsen
1

Se puede leer en la misma página:

...

En consecuencia, Git no registra explícitamente las relaciones de revisión de archivos en ningún nivel por debajo del árbol de código fuente.

...

Es un poco más costoso examinar el historial de cambios de un solo archivo que todo el proyecto. Para obtener un historial de cambios que afecten a un archivo determinado, Git debe recorrer el historial global y luego determinar si cada cambio modificó ese archivo. Sin embargo, este método de examinar el historial permite que Git produzca con igual eficiencia un único historial que muestre los cambios en un conjunto arbitrario de archivos. Por ejemplo, un subdirectorio del árbol de origen más un archivo de encabezado global asociado es un caso muy común.

...

Por lo tanto, puede volver a las revisiones anteriores de un archivo y comparar dos archivos.

Tamara Wijsman
fuente
1

De hecho, git guarda deltas de archivos, pero los guarda como un delta de todo el árbol de archivos.

Para ver las diferencias entre versiones, realice una de las siguientes acciones:

  1. git diff : muestra las diferencias entre la última versión registrada y los archivos que se han cambiado, pero que no se han git addejecutado en ellos.
  2. git diff --cached - muestra las diferencias entre la versión anterior y lo que todos los archivos que se han git addejecutado, pero que no se han confirmado
  3. git diff commitid : muestra las diferencias entre el directorio de trabajo actual y un commit anterior como se especifica con el commitid
  4. git diff commita..commitb - muestra las diferencias entre dos commits, a y b. Los commits también podrían ser nombres simbólicos como ramas o etiquetas.
canto
fuente
Esta respuesta no es realmente correcta. Todos estos comandos se pueden aplicar a un conjunto arbitrario de archivos, así como todo el árbol - sólo tiene que añadir los nombres de archivo al final ...
naught101