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.