Comandos de Git que podrían romper / reescribir el historial

¿Puede proporcionar una list de (todas, o las más comunes) las operaciones o commands que pueden comprometer la historia en git?

¿Qué debería evitarse por completo?

  1. Enmenda un compromiso después de un empujón de este ( git commit / git push / git commit --amend )
  2. Rebase hacia algo que ya ha empujado

Me gustaría que esta pregunta (si no lo hubiera hecho antes en otro lugar) se convierta en un tipo de reference sobre las operaciones evitables comunes en git .

Además, uso git reset mucho, pero no estoy completamente al tanto del posible daño que podría hacerle al repository (oa las copys de otros queueboradores). ¿Puede el git reset ser peligroso?

knittl ya compiló una buena list de los commands que reescriben la historia, pero yo quería basarme en su respuesta.

¿Puede proporcionar una list de […] las operaciones o commands que pueden comprometer la historia en git? ¿Qué debería evitarse por completo?

En primer lugar, no hay nada de malo en volver a escribir / borrar el historial per se ; después de todo, es probable que rutinariamente cree twigs de características, las mantenga estrictamente locales, luego elimine (después de fusionarlas o de que no lo llevan a ninguna parte) sin pensarlo dos veces.

Sin embargo, puede y seguramente tendrá problemas cuando rescriba / elimine localmente el historial al que otras personas ya han accedido y luego lo transfieran a un control remoto compartido.

Operaciones que deberían contar como reescribir / borrar el historial de un repository local

Por supuesto, existen forms tontas de corromper o eliminar el historial (por ejemplo, alterar el contenido de .git/objects/ ), pero están fuera del scope de mi respuesta.

Puede reescribir la historia de un repository local de varias maneras. La sección del libro de Pro Git titulada Reescribiendo la historia , menciona algunas

  • git amend --commit
  • git rebase
  • git filter-branch
  • BFG Repo Cleaner de Roberto Tyley (una herramienta de terceros)

Podría decirse que hay más. Cualquier operación que tenga el potencial de alterar o mover una reference no simbólica (twig o label) y hacer que apunte a una confirmación que no sea un descendiente de la sugerencia actual de la sucursal debe contar como la reescritura del historial local. Esto incluye:

  • git commit --amend : reemplaza el último commit;
  • Todas las forms de rebase (incluido el git pull --rebase );
  • git reset (ver un ejemplo a continuación);
  • git checkout -B y git branch -f : restablece una twig existente a una confirmación diferente;
  • git tag --force : recrea una label con el mismo nombre pero potencialmente apuntando a otra confirmación.

Cualquier eliminación de una reference no simbólica (twig o label) también se puede considerar eliminación de historial:

  • git branch -d o git branch -D
  • git tag -d

Podría decirse que eliminar una twig que se haya fusionado por completo con otra debería considerarse como una forma leve de eliminación de historial, si es que lo hace.

Las tags son diferentes, sin embargo. Eliminar una label liviana no es tan importante, pero eliminar una label anotada, que es un object genuino de Git, debería contar como eliminar el historial local.

Operaciones que reescriben / eliminan el historial de un repository remoto

Por lo que sé, solo un git push -f (equivalente a git push --force ) tiene el potencial de reescribir / borrar el historial en el repository remoto.

Dicho esto, es posible

  • deshabilite la capacidad de forzar la actualización de sucursales remotas a references de avance rápido, configurando receive.denyNonFastForwards en el server.
  • deshabilitar la capacidad de eliminar una twig que vive en un repository remoto, configurando receive.denyDeletes en el server.

Además, uso git reset mucho, pero no estoy completamente al tanto del posible daño que podría hacerle al repository (oa las copys de otros queueboradores). ¿Puede el git reset ser peligroso?

git-reset , como lo menciona knittl , generalmente cambia donde apunta una reference de twig. Este command puede ser peligroso, en la medida en que puede hacer que las confirmaciones alcanzables sean inalcanzables. Como una image vale más que mil palabras, considere la siguiente situación:

enter image description here

Estás en la twig master , que apunta a cometer D Ahora, digamos que corres, por ejemplo,

 git reset master~2 

Se considera que un restablecimiento parcial es la forma más benigna de reinicio, ya que "solo" cambia a donde apunta la ramificación actual, pero no afecta el área de preparación o su tree de trabajo. Dicho esto, simplemente cambiar a dónde apunta una twig de esa manera tiene ramificaciones: después de ese reinicio suave, terminarás con

enter image description here

Los compromisos C y D , que eran alcanzables desde el master antes del reinicio, ahora se han vuelto inalcanzables; en otras palabras, no son ancestros de ninguna reference (twig, label o CABEZA). Se podría decir que están en el " limbo del repository "; todavía existen en la database de objects de su Git repo, pero ya no se enumerarán en la salida del git log de git log .

Si en verdad encontraste que las confirmaciones son valiosas antes del reinicio, deberías hacerlas accesibles de nuevo haciendo que una reference (por ejemplo, otra twig) apunte a cometer D nuevamente. De lo contrario, confirma que C y D terminarán muriendo de verdad cuando Git ejecuta su recolección automática de basura y elimina objects inalcanzables.

En teoría, fish puede comprometer a D con el reflog , pero siempre existe el riesgo de que se olvide de las confirmaciones inalcanzables o de que no pueda identificar qué input del reflog corresponde a commit D

En conclusión, sí, git-reset puede ser peligroso, y es una buena idea asegurarse de que la punta actual de la twig que está a punto de restablecer siga siendo alcanzable después del reinicio. Si es necesario, cree otra twig allí antes del reinicio, por si acaso, como una copy de security; y si está seguro de que quiere olvidar esas confirmaciones, siempre puede eliminar esa twig más adelante.

La parte superior de mi cabeza:

  • git commit --amend reescribirá el compromiso anterior
  • git rebase puede reescribir múltiples commits (también se llama a rebase cuando usas git pull con la --rebase flag o la branch.$name.rebase config)
  • git filter-branch puede reescribir múltiples commits
  • git push -f puede cambiar la confirmación a la que apunta una bifurcación (lo mismo aplica para el git push origin +branch syntax de git push origin +branch )
  • git reset puede cambiar la confirmación a la que apunta una bifurcación
  • git branch -f puede cambiar la confirmación a la que apunta una bifurcación (recreando una bifurcación con el mismo nombre)
  • git checkout -B puede cambiar la confirmación a la que apunta una twig (recreando una twig con el mismo nombre)