your you without what track the that still retrieve que pointer made log helps have hace discarded different commits are and git reachability reflog

you - what is the git command to move branch pointer to different commit without checkout ?



git reflog expire y git fsck-inalcanzable (1)

Descargo de responsabilidad: esta pregunta es meramente informativa y no representa un problema real que estoy experimentando. Solo estoy tratando de descubrir cosas por el bien de eso (porque me encanta descifrar cosas, y sé que tú también).

Así que estaba jugando con git, intentando caducar un commit modificado. Mi reflog se ve así:

4eea1cd HEAD@{0}: commit (amend): amend commit ff576c1 HEAD@{1}: commit: test: bar 5a1e68a HEAD@{2}: commit: test: foo da8534a HEAD@{3}: commit (initial): initial commit

Lo que significa que hice dos confirmaciones ( da8534a y 5a1e68a ), luego una tercera confirmación ff576c1 que modifiqué con 4eea1cd .

Tal como se esperaba, mi git log ve algo así:

* 4eea1cd (HEAD, master) amend commit * 5a1e68a test: foo * da8534a initial commit

De lo que (aunque sé) sobre la caducidad de las confirmaciones, algún día (lo más probable, en 30 días por defecto) git gc debería recopilar ff576c1 . Ahora no quiero esperar 30 días para ver que suceda, así que comienzo a ejecutar algunos comandos, primero:

git fsck --unreachable --no-reflogs

Lo cual, tal como lo esperaba de nuevo, me da:

unreachable blob 5716ca5987cbf97d6bb54920bea6adde242d87e6 unreachable tree 1e60e555e3500075d00085e4c1720030e077b6c8 unreachable commit ff576c1b4b6df57ba1c20afabd718c93dacf2fc6

ff576c1 que voy a vencer ese pobre solo ff576c1 commit, luego ejecuto git reflog expire :

git reflog expire --dry-run --expire-unreachable=now --all

Que, esa vez, me da:

would prune commit: test: bar would prune commit (amend): amend commit

Al principio pensé que mi HEAD no hacía referencia al master , pero como se puede ver en la salida del git log que proporcioné anteriormente, realmente lo hace. Además, cat .git/HEAD confirma que ( ref: refs/heads/master De ref: refs/heads/master refs ref: refs/heads/master ). De todos modos, aunque eso fue una tontería, ya que 4eea1cd es el jefe de mi rama master .

Así que aquí estoy, todos confundidos de que estos dos comandos no me darán los mismos compromisos, y me pregunto cómo demonios podría ser imposible alcanzar el 4eea1cd , ya que es la punta real de mi rama master .

¿Alguna idea de lo que está pasando?

EDITAR : Me acabo de dar cuenta si agrego la opción --rewrite a git reflog expire , así:

git reflog expire --dry-run --expire-unreachable=now --all --rewrite

Entonces solo obtengo el commit modificado:

would prune commit: test: bar

Todavía no entiendo, porque según git help reflog :

--rewrite While expiring or deleting, adjust each reflog entry to ensure that the old sha1 field points to the new sha1 field of the previous entry.

Lo que no tiene sentido en mi caso. Bueno, al menos no lo entiendo, ya que obviamente cambia algo.


Este comportamiento proviene de una interacción entre la filosofía de diseño de reflog y los requisitos de la recolección de basura.

Para que el recolector de basura elimine de forma segura una confirmación, todas las referencias a esa confirmación deben eliminarse, incluidas las referencias en las entradas de reutilización. A pesar de la aparición de reflog show , cada entrada de reflog contiene dos identificadores SHA1: el valor de la referencia antes del cambio y el valor de la referencia después del cambio. Para garantizar la recolección segura de basura, el reflog expire simplemente elimina cualquier entrada en la que uno de los dos SHA1 identifique un compromiso inalcanzable.

En su caso, el valor previo al cambio de la entrada más reciente de reflog se refiere a un compromiso inalcanzable. A pesar de que el compromiso identificado por el valor posterior al cambio todavía es alcanzable, el reflog expire elimina la entrada.

Este diseño es fácil de implementar y da como resultado un registro incompleto pero preciso.

la opción --rewrite

Desafortunadamente, la eliminación de una entrada que hace referencia a un compromiso aún accesible tiene un par de problemas:

  • queda un hueco en el registro
  • Se pierde información útil relacionada con las confirmaciones aún accesibles.

La opción --rewrite resuelve estos problemas cambiando el comportamiento de la siguiente manera:

  • Como antes, se eliminan las entradas en las que no se puede acceder al compromiso identificado por el SHA1 posterior al cambio.
  • Las entradas en las que no se puede acceder a la confirmación previa al cambio se modifican para cerrar la brecha que dejó la entrada eliminada (el SHA1 previo al cambio se establece en el valor del SHA1 posterior al cambio de la entrada anterior).

Desafortunadamente, la modificación de la entrada da como resultado un registro que ya no refleja con precisión el historial de la referencia. Por ejemplo, la razón del cambio puede que ya no tenga sentido después de la reescritura. Es por --rewrite que --rewrite no es el predeterminado.