¿Eliminar una rama en git la elimina del historial?

190

Viniendo de svn, comenzando a familiarizarme con git.

Cuando una rama se elimina en git, ¿se elimina del historial?

En svn, puede recuperar fácilmente una rama al revertir la operación de eliminación (fusión inversa). Como todas las eliminaciones en svn, la rama nunca se elimina realmente, solo se elimina del árbol actual.

Si la rama se elimina realmente del historial en git, ¿qué sucede con los cambios que se fusionaron desde esa rama? ¿Se retienen?

Ken Liu
fuente

Respuestas:

251

Las ramas son solo punteros para cometer en git. En git cada commit tiene un árbol fuente completo, es una estructura muy diferente de svn donde todas las ramas y etiquetas (por convención) viven en 'carpetas' separadas del repositorio junto al 'tronco' especial.

Si la rama se fusionó con otra rama antes de eliminarse, todos los commits seguirán siendo accesibles desde la otra rama cuando se elimine la primera rama. Permanecen exactamente como estaban.

Si la rama se elimina sin fusionarse con otra rama, los commits en esa rama (hasta el punto en el que la bifurcación de un commit que todavía es accesible) dejará de ser visible.

Los commits aún se conservarán en el repositorio y es posible recuperarlos inmediatamente después de la eliminación, pero eventualmente se recolectarán basura.

CB Bailey
fuente
3
Gracias por la respuesta. ¿Podría aclarar lo que quiere decir con "cada confirmación tiene un árbol fuente completo"? Según tengo entendido, cada commit en git es un conjunto de deltas que se refieren a un commit padre, no a un árbol completo.
Ken Liu
2
@Ken Liu: Una confirmación contiene punteros a cero o más confirmaciones principales, un objeto de árbol y algunos metadatos sobre la confirmación. El commit, por lo tanto, identifica de manera única tanto un árbol de origen par como, cuando se ve contra sus padres, los cambios que introdujo.
CB Bailey
9
@Ken Liu: Depende exactamente de lo que haya sido por 'contener', pero sí, esencialmente cada confirmación contiene un árbol completo. En la base de datos de objetos, los objetos se indexan por id, de modo que los objetos se comparten entre todos los objetos (árboles y confirmaciones) que hacen referencia a ellos, de modo que la sobrecarga de almacenamiento implícita no es tan mala como parece inicialmente. git también tiene una optimización de almacenamiento eficiente (archivos de paquete) que hacen un uso aún más eficiente del espacio en disco.
CB Bailey
22
"eventualmente serán recolectados de basura" - ¿Cuándo?
BadHorsie
77
@BadHorsie, depende .
AliOli
86

En Git, las ramas son solo punteros (referencias) para los commits en un gráfico acíclico dirigido (DAG) de commits. Esto significa que al eliminar una rama solo se eliminan las referencias a las confirmaciones, lo que puede hacer que algunas confirmaciones en el DAG sean inalcanzables, por lo tanto invisibles. Pero todas las confirmaciones que se encontraban en una rama eliminada aún estarían en el repositorio, al menos hasta que se eliminen las confirmaciones inalcanzables (por ejemplo, usando git gc).

Tenga en cuenta que git branch -dse negaría a eliminar una rama si no puede estar seguro de que eliminarla no dejaría confirmaciones inalcanzables. Debe usar el más fuerte git branch -Dpara forzar la eliminación de una rama si puede dejar confirmaciones inalcanzables.

Tenga en cuenta también que las confirmaciones inalcanzables, si están presentes, son solo aquellas confirmaciones entre el último consejo de una rama eliminada y una confirmación que se fusionó con otra rama existente, cualquier confirmación etiquetada o el punto de ramificación; lo que sea más tarde Por ejemplo en la siguiente situación:

---- O ---- * ---- * ---- / M ---- * <- maestro <- CABEZA
     \ /
      \ --. ---- .-- / - x --- y <- rama eliminada

solo las confirmaciones 'x' e 'y' serían inaccesibles después de eliminar la rama.

Si operó en una sucursal eliminada dentro del gc.reflogExpireperíodo predeterminado de 90 días, tendría la última sugerencia de una sucursal eliminada registrada en HEAD reflog (ver git reflog show HEAD, o git log --oneline --walk-reflogs HEAD). Debería poder usar HEAD reflog para recuperar el puntero eliminado. Tenga en cuenta también que, en este caso, las confirmaciones inalcanzables en solo una rama eliminada estarían protegidas de la poda (eliminación) dentro del gc.reflogExpireUnreachableperíodo, que por defecto es de 30 días.

Si no puede encontrar la punta de una rama recién eliminada en el registro de HEAD, puede intentar usar git fsckpara encontrar "commit inalcanzable <sha1>" y examinarlos (a través de git show <sha1>o git log <sha1>) para encontrar la punta de la rama eliminada.

Independientemente de cómo encuentre la punta de una rama eliminada, puede deshacer la eliminación o, más bien, volver a crear una rama recién eliminada utilizando

git branch <deleted-branch> <found-sha1-id>

Sin embargo, tenga en cuenta que se perdería el registro de una rama.


También hay un script git-resurrect.sh en el contrib/que ayuda a encontrar rastros de una punta de rama con un nombre de pila y resucitarlo (recuperarlo).

Jakub Narębski
fuente
1
¡Increíble! git reflog show HEADenumeré el commit y creé una nueva rama tal como dijiste, perfecta.
Steven Almeroth
2

Si le preocupan las ramas eliminadas accidentalmente y ya no tiene una copia local de su repositorio, existen extensiones para servidores Git empresariales como Gerrit que detectarán reescrituras del historial y eliminaciones de sucursales, las respaldarán bajo una referencia especial para que puedan se puede restaurar si es necesario y no se eliminará mediante la recolección de basura. Los administradores de Gerrit aún pueden eliminar confirmaciones seleccionadas si es necesario por razones legales.

Johanned Nicolai
fuente