¿Qué hace git log –all do en el context de la diferencia entre twigs?

Tengo un historial de commit de la siguiente manera:

* 7a5841d - (6 hours ago) commit messageA (master) | * 1552e99 - (6 hours ago) commit messageB (HEAD -> feature1) | * 2d4a3bd - (6 hours ago) commit messageC | * 31513f7 - (6 hours ago) commit messageD | * 3335afb - (7 hours ago) commit messageE |/ * 5be4cf7 - (27 hours ago) commit messageF (origin/master, origin/HEAD) | * 870f217 - (27 hours ago) commit messageG (origin/develop) | * 70f1973 - (27 hours ago) commit messageH |/ * 50e3bba - (27 hours ago) commit messageI $ git log --oneline master ^feature1 --no-merges 7a5841d commit messageA $ git log --all --oneline master ^feature1 --no-merges 7a5841d commit messageA 870f217 commit messageG 70f1973 commit messageH 

¿Qué hace git log --all hacer aquí? ¿Por qué devuelve los dos compromisos adicionales?

Supongo que el primero realmente es el set completo de todas las confirmaciones (no tengo razones para creer que no lo es, pero podría haber más que no podemos ver, por ejemplo, en reflogs, eso no afecta esta respuesta, pero es un punto sutil en ambos sentidos).

Lo que significa todos los medios son todas las references (más HEAD ). Pero esa no es toda la historia aquí. (También voy a dejar de lado --no-merges ya que no hay fusiones de todos modos.)

Referencias

Comencemos con la noción de references , a diferencia de las twigs, las tags y las twigs de seguimiento remoto. Una reference es la forma completamente general: las tres variedades específicas (twig, label, twig de seguimiento remoto) son un tipo de reference. Un nombre de twig como master es, en general, solo una breve forma de decir el nombre completo de reference, refs/heads/master . Un nombre de label como v1.3 es una manera breve de decir refs/tags/v1.3 , y un nombre de twig de seguimiento remoto como origin/develop es una manera breve de decir refs/remotes/origin/develop .

Hay más references posibles: por ejemplo, el stash es corto para refs/stash . Si tiene un escondite activo (de git stash save ), tiene un refs/stash . Eso habría aparecido aquí, y no lo hizo; entonces no tienes uno Pero, todos lo includeían, si lo hicieras. También hay "notas" Git opcionales bajo refs/notes , y puede haber más. Cualquier cosa que comience con refs/ es una reference, y la bandera --all consigue todos! (Además, como mencioné, HEAD , pero por lo general eso no importa. Tenga en count que HEAD no comienza con refs/ por lo que nominalmente no es una reference , ¡aunque es la que Git usa principalmente por defecto!)

Puede usar --branches para significar "todas las twigs" (todo en refs/heads/* ), --tags para significar "todas las tags" ( refs/tags/* ), y --remotes para significar "all remote-tracking" twigs "( refs/remotes/* ). Usando algunos o todos estos, puede dejar de lado los elementos adicionales, si existen.

Nombres cortos como master

Casi siempre que utilizas un nombre como master , Git realiza el process de búsqueda de reference de seis pasos descrito en la documentation de gitrevisions . Haga clic en el enlace y encuentre la list de seis pasos, y tenga en count que la traducción de master a refs/heads/master es en realidad el paso cuatro . Si hubiera un refs/tags/master , eso sucede en el paso tres y esa es la reference que obtendría.

(Digo casi cualquier momento aquí porque algunos commands, como el git checkout , tratan de tratar primero un nombre como nombre de una sucursal, y solo luego pasan por el process de seis pasos para resolver el nombre. Así que git checkout master comtesting la twig , no la label, si hay tanto un master twig como un master label. El command de git log no: si ambos existen, ¡obtienes la label aquí! La versión abreviada es "no hagas eso" 🙂 – nunca te configures con una twig llamada X y una label llamada X. Es muy confuso.)

Referencias negadas, accesibilidad y el gráfico de confirmación

Tu último command es:

 git log --all --oneline master ^feature1 --no-merges 

No necesita master aquí, porque --all significa todas las references , y master significa "encontrar una reference master " (probablemente la twig). Ya ha sido encontrado.

La ^feature1 , sin embargo, es crucial. Cuando Git va a enumerar todas las confirmaciones alcanzables , tiene en count todos los lugares que le dijo que comenzara; en este caso, --all significan "todas las references" – pero los reemplaza con todos los lugares que le indicó que detuvieran . Un prefijo hat ^ niega una reference: significa "poner esto en la list de detención". Git encuentra la confirmación específica que feature1 nombres; podemos ver arriba que esto es 1552e99 .

Entonces Git pone 1552e99 en la list de "detener". Pero no solo se detiene allí: encuentra que todos los compromisos se pueden 1552e99 desde 1552e99 (post B). Eso comienza con su primer y único compromiso principal, que es 2d4a3bd ( 2d4a3bd ). Sin 2d4a3bd Commit 2d4a3bd tiene un padre: eso es commit 31513f7 ( 31513f7 ); y que tiene un padre, 3335afb (messageE), que tiene el padre 5be4cf7 (messageF).

Sin embargo, 5be4cf7 count que el padre de 5be4cf7 es 50e3bba (messageI), omitiendo las otras dos confirmaciones. (Siga las líneas que conectan los asteriscos en la salida del git log --graph . Esto puede ser más fácil sin --oneline , al less al principio; es casi seguro más fácil en un visor gráfico como gitk o alguna GUI).

Cuando llegamos a 50e3bba nos detenemos: no tiene padres. Es un commit raíz (que solo significa "un commit sin padres"). Así que eso completa nuestra list de confirmaciones de "detención".

Ahora git log --all puede ir a ver todas las references. Hay un total de cuatro: master , feature1 , origin/master y origin/develop . (O tal vez hay cinco o seis: también deberíamos considerar HEAD y origin/HEAD . Sin embargo, esos dos últimos son references simbólicas , como en, simplemente nombran otras references existentes. Así que se doblan y volvemos a bajar solo cuatro.)

Esos cuatro nombres resuelven commits 7a5841d ( master ), 1552e99 ( HEAD -> feature1 ), 5be4cf7 ( origin/master, origin/HEAD ) y 870f217 ( origin/develop ). Entonces git log pone -o intenta poner- esos cuatro commits en la list de cosas que se mostrarán.

1552e99 , sin embargo, está en la list de detención. Entonces Git no lo muestra; lo expulsa de la list "para mostrarse" (o nunca lo pone allí, lo que tiene el mismo efecto). Git elige uno de los tres commits restantes y lo muestra. Podemos ver que seleccionó 7a5841d . 1

Git intenta agregar las 7a5841d de 7a5841d a la "list de espectáculos", pero el padre 5be4cf7 es 5be4cf7 . Eso ya está en la list "detener", a través de ^feature1 . O es expulsado o nunca lo hace.

Eso deja solo 870f217 en la list de espectáculos. Git lo muestra a continuación, y luego agrega sus padres a la list de espectáculos. Tiene solo un padre, 70f1973 . Entonces eso está ahora en la list de espectáculos; Git te lo muestra. Git intenta agregar su padre a la list de espectáculos, pero eso es 50e3bba , que está en la list de detención.

La list de espectáculos ahora está vacía, por lo que el git log ha finalizado.


1 Hay otro punto difícil aquí. Cuando Git está en esta position de elegir una confirmación de una posible acumulación de posibles compromisos, se necesita la date de compromiso numéricamente mayor . Si realiza una confirmación que tiene date muy lejana en el futuro, colóquela en una twig o label para que sea accesible desde --all , y ejecute git log --all , que la confirmación futura salga primero siempre.