remote - git push tag
Listado y eliminación de confirmaciones de Git que no están bajo ninguna rama(¿colgando?) (7)
Tengo un repositorio de Git con muchos compromisos que no están bajo ninguna rama en particular, puedo git show
, pero cuando trato de enumerar las ramas que los contienen, no informa nada.
Pensé que este es el problema de commit / tree colgando (como resultado de la rama -D), así que eliminé el repositorio, pero todavía veo el mismo comportamiento después de eso:
$ git fetch origin
$ git fsck --unreachable
$ git fsck
Sin salida, nada colgando (¿verdad?). Pero el compromiso existe
$ git show 793db7f272ba4bbdd1e32f14410a52a412667042
commit 793db7f272ba4bbdd1e32f14410a52a412667042
Author: ...
y no es alcanzable a través de ninguna rama como
$ git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042
no da salida
¿Cuál es exactamente el estado de ese compromiso? ¿Cómo puedo hacer una lista de todas las confirmaciones en un estado similar? ¿Cómo puedo eliminar commits como esos?
Sin salida, nada colgando (¿verdad?)
Tenga en cuenta que las confirmaciones a las que se hace referencia desde su reflog se consideran alcanzables.
¿Cuál es exactamente el estado de ese compromiso? ¿Cómo puedo hacer una lista de todas las confirmaciones con estado similar?
Pase --no-reflogs
para convencer a git fsck
que se los muestre.
¿Cómo puedo eliminar commits como esos?
Una vez que expiren sus entradas de reflog, esos objetos también serán limpiados por git gc
.
La caducidad está regulada por las gc.pruneexpire
, gc.reflogexpire
y gc.reflogexpireunreachable
. Cf. git help config
.
Los valores predeterminados son todos bastante razonables.
Accidentalmente pulsé la misma situación y descubrí que mis depósitos contienen referencias a la confirmación inalcanzable, y por lo tanto, la supuesta obligación inalcanzable era alcanzable desde escondites.
Esto fue lo que hice para hacerlo realmente inalcanzable.
git stash clear
git reflog expire --expire-unreachable=now --all
git fsck --unreachable
git gc --prune=now
Para eliminar todas las confirmaciones pendientes y aquellas a las que se puede acceder desde los reflogs, haga lo siguiente:
git reflog expire --expire-unreachable=now --all
git gc --prune=now
Pero asegúrese de que esto es lo que quiere. Te recomiendo que leas las páginas man, pero esta es la esencia:
git gc
elimina objetos inalcanzables (commits, trees, blobs (files)). Un objeto es inalcanzable si no es parte del historial de alguna rama. En realidad es un poco más complicado:
git gc
hace algunas otras cosas pero no son relevantes aquí y no son peligrosas.
Los objetos inalcanzables que tienen menos de dos semanas no se eliminan, por lo que usamos --prune=now
que significa "eliminar objetos inalcanzables que se crearon antes".
Los objetos también pueden ser alcanzados a través del reflog. Mientras que las sucursales registran la historia de algún proyecto, los reflogs registran el historial de estas ramas. Si modificas, restableces, etc., las confirmaciones se eliminan del historial de la sucursal, pero git las conserva en caso de que te des cuenta de que cometiste un error. Los Reflogs son una forma conveniente de descubrir qué operaciones destructivas (y otras) se realizaron en una rama (o HEAD), lo que facilita deshacer una operación destructiva.
Por lo tanto, también debemos eliminar los reflogs para eliminar todo lo que no se puede acceder desde una sucursal. Lo hacemos al caducar --todos los reflogs. De nuevo, git guarda un poco de los reflogs para proteger a los usuarios, así que de nuevo tenemos que decirle que no lo haga: --expire-unreachable=now
.
Como utilizo principalmente el reflog para recuperarme de las operaciones destructivas, suelo usar --expire=now
lugar, lo que elimina por completo los reflogs.
Tuve el mismo problema, aún después de seguir todos los consejos en este hilo:
git reflog expire --expire-unreachable=now --all
git gc --prune=now
git fsck --unreachable --no-reflogs # no output
git branch -a --contains <commit> # no output
git show <commit> # still shows up
Si no es un reflog y no es una sucursal, ... ¡debe ser una etiqueta !
git tag # showed several old tags created before the cleanup
git tag -d <tagname>
las etiquetas con la etiqueta git tag -d <tagname>
y rehice la limpieza, y las confirmaciones anteriores desaparecieron.
Tuve un problema similar. Ejecuté git branch --contains <commit>
, y no devolvió ningún resultado como en la pregunta.
Pero incluso después de ejecutar
git reflog expire --expire-unreachable=now --all
git gc --prune=now
mi compromiso todavía era accesible usando git show <commit>
. Esto se debió a que se etiquetó uno de los commits en su "branch" separada / colgada. Eliminé la etiqueta, volví a ejecutar los comandos anteriores y estaba dorado. git show <commit>
returned fatal: bad object <commit>
- exactamente lo que necesitaba. Espero que esto ayude a alguien más que estaba tan atrapado como yo.
git gc --prune=<date>
para eliminar objetos anteriores a hace dos semanas. Puede establecer una fecha más reciente. Pero, los comandos git que crean objetos sueltos generalmente ejecutarán git gc --auto (que poda los objetos sueltos si su número excede el valor de la variable de configuración gc.auto).
¿Estás seguro de que deseas eliminar estos commits? La configuración predeterminada de gc.auto garantizará que los objetos sueltos no ocupen una cantidad irrazonable de memoria, y almacenar objetos sueltos durante un tiempo es una buena idea. De esta forma, si se da cuenta mañana de que su sucursal eliminada contenía una confirmación que necesitaba, puede recuperarla.
git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042
Probablemente solo necesite ser
git branch -a --contains 793db7f272ba4bbdd1e32f14410a52a412667042
para informar también sobre las sucursales de los controles remotos