¿Por qué 'git rebase' mantiene el historial de sucursales networkingistribuido?

Como lo entiendo de http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html, la twig rebasada se 'mueve' a otra.

Lo que veo durante mis testings, sin embargo, muestra que las confirmaciones de la twig rebasada permanecen en el historial, por lo que se duplican efectivamente.

Antes de rebase:

Después de rebase:

Tal vez me falta algo o no entiendo completamente el propósito de rebase o ambos.

Si lo que veo es el comportamiento previsto, entonces ¿por qué es así?

Hay dos fenóless separados aquí.

  1. La captura de pantalla que ha publicado, desde gitk, muestra todavía la antigua confirmación. Así es como funciona gitk; Si vuelves a cargar presionando Ctrl + F5 en lugar de solo F5 (Es decir, Archivo> Volver a cargar en lugar de Archivo> Actualizar para los usuarios del mouse) verás que la confirmación anterior desaparece porque ya no es relevante.

  2. Hay muchas operaciones en Git que crean commits. Aún más que crean objects de files o treees en el almacén de files. El hecho de que muchos de estos objects ya no se usen es irrelevante.

    Esto tiene un montón de ventajas. En su ejemplo, significa que si decidió que su rebase era una mala idea, su antigua confirmación aún existe y puede recuperarse. Incluso hay una syntax útil para él: topic@{1} hace reference a la confirmación a la que apuntaba ese topic antes de la última vez que se movió; aquí eso sería inmediatamente antes de la rebase.

    El model de objects Git es inteligente sobre este tipo de cosas. Tener un compromiso extra como este por ahí ocupa muy poco espacio extra. Para una database como la que está describiendo, esperaría que conservar la antigua twig costara unos cientos de bytes.

    Por supuesto, eso se acumula con el time. Entonces git gc (que se ejecuta automáticamente por ciertos commands cada cierto time) ejecuta git prune . Y git prune searchá las confirmaciones y los objects que son antiguos y que ya no son relevantes y los eliminará para usted.

Nada de esto significa que su rebase no ha funcionado, solo que la idea de los commits "de rebase" de la database es una simplificación. Lo que realmente hace la rebase es aplicar las diferencias entre cada compromiso y su padre a la nueva bifurcación, y crea una nueva confirmación con esas diferencias para cada compromiso en la bifurcación anterior. Luego actualiza la twig de modo que, si observa el historial de la sucursal, es como si esas confirmaciones se hubieran movido.

En resumen, rebase es una forma de aplicar compromisos desde una parte del tree a un punto de partida diferente. Puede copyr esos cambios, pero no los moverá .

Restring que los commit de git son inmutables: una vez que algo tiene un hash, nunca cambia. Eso significa que cuando restaure algunos cambios además de otro cambio, los valores hash son necesariamente diferentes, por lo que git se mantendrá alnetworkingedor del anterior y del nuevo.

Sin embargo, si ningún nombre de sucursal apunta a la confirmación anterior ("agregar file2" en su ejemplo), luego de un par de semanas, el recolector de basura automático de git eliminará la confirmación anterior de su repository. (¿Por qué dos semanas? De ese modo, si cambia de opinión, puede recuperar el compromiso anterior de git reflog ). Generalmente, esto es algo bueno, hace que sea más difícil perder datos por crash, pero si el file es extremadamente grande, puedes usar una combinación de git prune y git gc para recortar los datos networkingundantes.

Rebase es un command que reescribe el historial. Pero gracias a git tu historia no está perdida. Puede retroceder hasta que el recolector de basura git borre esas confirmaciones pendientes.

… la twig rebasada se 'mueve' a otra.

Esa es una forma de expresslo, pero no del todo acertada.

La mejor manera de pensar en un git repo es pensarlo como una composition de dos cosas: un gráfico acíclico dirigido de confirmaciones inmutables, cada una representando una versión de su software (o lo que sea que esté en el repository), y un set de twigs variables de puntero ( maestro, etc.).

Supongamos que comienza con un repository con tres confirmaciones que se ve así:

 a--> b \-> c 

donde el puntero de origen / ramificación principal apunta hacia b y el puntero de la ramificación principal apunta a c . En realidad, tiene tres versiones diferentes de su software aquí, a , c .

Si luego decides volver a calcular c on to b , terminarás con un repository que se ve así:

 a--> b--> c' \-> c 

con el puntero de la twig principal cambiado para que apunte a c' . "Al presionar esta confirmación", se enviará la confirmación c' al repository de origen, se cambiará el puntero de la twig maestra del repository de origen al punto a c' y se cambiará el puntero de la twig de origen / maestro para que coincida.

Notará que c' es una confirmación diferente de c , que todavía está presente, y ahora tiene cuatro versiones de su software. El c' commit hace moralmente el mismo cambio en b que c hizo a a (o eso es lo que uno espera, presumiendo que editó cualquier conflicto de manera apropiada).

c ya no tiene ningún puntero de bifurcación apuntando hacia él (bueno, fuera del reflog, en realidad), y por lo tanto será basura recolectada en algún momento posterior durante la operación normal de git.

(Git también realiza algunos trucos de compression sofisticados para almacenar todas estas versiones diferentes [y completas] de tu software en less espacio que si fueran todas desprotegidas individualmente, pero eso no es realmente algo que necesites, o incluso deberías, molestarte en pensar. )

En una charla informal, nos referimos a esta operación como "cambiar la twig principal ", pero en realidad, lo que estás haciendo es crear una nueva twig y cambiar a lo que se refiere el maestro de la twig anterior a la nueva.