git: ¿por qué puedo pagar la confirmación que eliminé?

5 minutos de lectura

Tengo una rama con tres confirmaciones:

mybranch: a -> b -> c

Lo empujé al repositorio remoto. Entonces decidí que no quiero mantener las confirmaciones. b y Casí que los eliminó como se describe aquí:

git reset --hard HEAD~1
git reset --hard HEAD~1
git push origin mybranch -f

Posteriormente, revisé git log y confirmó que solo el commit un era visible. Sin embargo:

  • Todavía puedo pagar los compromisos b y C. ¿Porqué es eso?
  • cuando usé SourceTree para buscar mi repositorio git, aún podía ver estas confirmaciones en mi rama (aunque la confirmación actual un se denotó correctamente como la confirmación en la que estaba actualmente). Usé git bash para verificar que estaba en la confirmación correcta y que mi HEAD no estaba en el estado separado.

¿Qué tiene de malo el procedimiento que usé? ¿Por qué mantuvo los compromisos? b y C? ¿Cómo puedo eliminarlos por completo?

En realidad, eliminar un compromiso es bastante difícil en git, por diseño. Muchos comandos que la gente pensar elimine confirmaciones (como rebase o reinicio), en realidad solo haga que esas confirmaciones sean “inaccesibles”, lo que hace que la salida predeterminada de varios comandos y herramientas los excluya.

Es relativamente raro que la razón para eliminar una confirmación justifique el costo. A veces, una confirmación contiene información confidencial (aunque, en ese caso, casi siempre es mejor considerar la información comprometida, ya sea que se esfuerce o no por eliminarla del repositorio). Tal vez una confirmación contenga archivos binarios excesivamente grandes que no están presentes en ninguna otra confirmación, inflando el repositorio. Si todo se reduce a querer “ocultar” un “error” para que el repositorio se vea perfecto, no perdería el tiempo en eso.

Pero si desea eliminar la confirmación, esto es lo que necesita saber:

Primero, debe eliminar todo el conocimiento de la confirmación. Su reset los comandos lo han hecho “inaccesible” (por punteros principales) desde la rama en la que ddi el resets. Si hay otras ramas que pueden llegar a las confirmaciones, deben ser reset o rebased lejos de la confirmación (o eliminada). Si hay etiquetas en las confirmaciones eliminadas, es necesario moverlas o eliminarlas. Hay casos especiales en los que otros árbitros podrían señalar las confirmaciones, pero asumiré que no se aplican. (Sería cosas como reemplazos o referencias de respaldo de filter-branch… Básicamente, si puede encontrar el SHA para cualquiera de los compromisos en el .git/packed-refs archivo o en cualquier archivo bajo refsentonces se necesita alguna acción para remediarlo).

Una vez que se eliminan todas las referencias, la confirmación queda “colgada”; pero aún puede ser accesible a través de reflog. Puedes intentar caducar los reflogs

git reflog expire --expire=all --all

Nunca he tenido mucha suerte con eso (lo que probablemente solo significa que nunca recuerdo los argumentos correctos); Siempre termino haciendo algo como

rm -r .git/logs

La desventaja en cualquier caso es que pierdes todos de su información de reflog. Puede ser más selectivo con respecto a qué reflogs expira. (Probablemente necesite HEAD y cualquier rama desde la cual las confirmaciones son (o eran) accesibles). Incluso podría usar delete en vez de expire para buscar entradas de reflog individuales. Nuevamente, todo depende de cuánto esfuerzo quieras poner en esto.

Entonces, una vez que no haya refs ni reflogs que puedan llegar a la confirmación, gc se puede usar para eliminar físicamente la confirmación del repositorio local.

git gc --aggressive --prune=now

Pero ahora todavía hay un problema: si alguna vez se presionaron las confirmaciones, el control remoto todavía las tiene; y presionar ahora no los eliminará del control remoto. (Al presionar se actualizan las referencias remotas y, según sea necesario, agrega objetos para completar la historia; pero no elimina objetos del control remoto).

Si el control remoto es solo un repositorio en un recurso compartido de archivos (o un servidor web que controla, o lo que sea): puede iniciar sesión en el servidor y limpiarlo de la misma manera que limpió su local. (Si ha presionado refs, entonces esa parte ya está hecha; pero es posible que deba limpiar reflogs y tendrá que ejecutar gc.)

Si el control remoto está alojado (github, gitlab, TFS, bitbucket…), entonces depende de a qué acceso gc es proporcionado por el anfitrión. En TFS (al menos en las versiones que he usado) estás arriba de un árbol; en el mejor de los casos, podría eliminar y volver a crear el repositorio. Otros servidores host pueden proporcionar la capacidad de activar gco incluso puede ejecutar gc automáticamente después de ciertos eventos; tendrías que consultar los documentos para el servicio/software de alojamiento.

avatar de usuario
kowsky

git reset no elimina las confirmaciones, restablece su rama a la confirmación dada (con HEAD~1, el predecesor directo de la confirmación HEAD actual de sus ramas). La confirmación del sucesor ya no forma parte de su rama. Si ninguna otra rama tiene la confirmación en su historial, la confirmación se convertirá en una confirmación ‘colgante’, no accesible para ninguna rama (Editar: en realidad se vuelve ‘inalcanzable’ al principio, y ‘colgante’ solo más tarde cuando ni siquiera es accesible por reflog; vea los comentarios a la respuesta vinculada a continuación). Si permanece así durante más tiempo, la recolección de basura de gits lo eliminará eventualmente. Hasta que lo haga, aún se podrá acceder a la confirmación mediante su id. SHA.

Esto es, de hecho, muy útil si estropeas el historial de tus sucursales. Con reflogu otros medios, puede obtener los ID de SHA de las confirmaciones perdidas y restaurar su trabajo si no se ha perdido durante demasiado tiempo.

SourceTree todavía muestra la conexión de b para a porque cada compromiso conoce a su predecesor. b y c sin embargo, ya no forman parte de su rama, ya que su compromiso HEAD es a.

No hay nada de malo en lo que hiciste, y no hay necesidad de intentar eliminar las confirmaciones. si continúa trabajando en el repositorio, eventualmente se eliminarán. Consulte esta respuesta para obtener detalles sobre la eliminación a través de la recolección de elementos no utilizados.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad