Saltar al contenido

¿Son “git fetch –tags –force” y “git pull “operaciones conmutativas?

Solución:

Esto se mete en uno de los rincones más oscuros de Git, pero al final la respuesta es “inicialmente no importa qué orden uses”. Sin embargo, recomiendo evitar git pull en general, y nunca usarlo en scripts de todos modos. Además, importa, de una manera diferente, precisamente cuando busca, como veremos a continuación. Así que recomiendo ejecutar el tuyo git fetch primero, luego simplemente no usar git pull en absoluto.

git fetch

Una llanura git fetch (sin --tags) utiliza una extraña actualización de etiqueta híbrida de forma predeterminada, aunque cada control remoto puede definir una opción de etiqueta predeterminada que anula esta predeterminada. El híbrido extraño es lo que citó: las etiquetas que apuntan a los objetos que se descargan del repositorio remoto se obtienen y almacenan localmente. El mecanismo subyacente para esto es un poco complicado y lo dejaré para más adelante.

Añadiendo --tags al git fetch argumentos tiene casi el mismo efecto que especificar, en la línea de comando, refs/tags/*:refs/tags/*. (Veremos la diferencia en un momento). Tenga en cuenta que esto no tiene el indicador de fuerza establecido en la especificación de referencia, sin embargo, las pruebas muestran que las etiquetas obtenidas se actualizan a la fuerza de todos modos.

Añadiendo --force tiene el mismo efecto que establecer el indicador de fuerza en cada especificación de referencia explícita. En otras palabras, git fetch --tags --force es aproximadamente equivalente a correr git fetch '+refs/tags/*:refs/tags/*': si el control remoto tiene etiqueta refs/tags/foo apuntando a comprometerse 1234567..., su Git reemplazará cualquier refs/tags/foo para que ahora tengas el tuyo refs/tags/foo también apuntando a cometer 1234567.... (Pero como se observa en la práctica, lo hace incluso con --tags.)

Tenga en cuenta que en todos casos, git fetch escribe información sobre lo que obtuvo en el archivo FETCH_HEAD. Por ejemplo:

$ cat .git/FETCH_HEAD
e05806da9ec4aff8adfed142ab2a2b3b02e33c8c        branch 'master' of git://git.kernel.org/pub/scm/git/git
a274e0a036ea886a31f8b216564ab1b4a3142f6c    not-for-merge   branch 'maint' of git://git.kernel.org/pub/scm/git/git
c69c2f50cfc0dcd4bcd014c7fd56e344a7c5522f    not-for-merge   branch 'next' of git://git.kernel.org/pub/scm/git/git
4e24a51e4d5c19f3fb16d09634811f5c26922c01    not-for-merge   branch 'pu' of git://git.kernel.org/pub/scm/git/git
2135c1c06eeb728901f96ac403a8af10e6145065    not-for-merge   branch 'todo' of git://git.kernel.org/pub/scm/git/git

(de una ejecución de búsqueda anterior sin --tags, y luego):

$ git fetch --tags
[fetch messages]
$ cat .git/FETCH_HEAD
cat .git/FETCH_HEAD 
d7dffce1cebde29a0c4b309a79e4345450bf352a        branch 'master' of git://git.kernel.org/pub/scm/git/git
a274e0a036ea886a31f8b216564ab1b4a3142f6c    not-for-merge   branch 'maint' of git://git.kernel.org/pub/scm/git/git
8553c6e5137d7fde1cda49817bcc035d3ce35aeb    not-for-merge   branch 'next' of git://git.kernel.org/pub/scm/git/git
31148811db6039be66eb3d6cbd84af067e0f0e13    not-for-merge   branch 'pu' of git://git.kernel.org/pub/scm/git/git
aa3afa0b4ab4f07e6b36f0712fd58229735afddc    not-for-merge   branch 'todo' of git://git.kernel.org/pub/scm/git/git
d5aef6e4d58cfe1549adef5b436f3ace984e8c86    not-for-merge   tag 'gitgui-0.10.0' of git://git.kernel.org/pub/scm/git/git
[much more, snipped]

Volveremos a esto en un momento.

La recuperación puede, dependiendo de las especificaciones de referencia adicionales que encuentre; esto generalmente está controlado por el remote.origin.fetch entradas de configuración: actualice algún conjunto de ramas de seguimiento remoto y cree o actualice algunas de sus etiquetas. Si está configurado como un espejo de recuperación, con su actualización refspec siendo +refs/*:refs/*, obtienes literalmente todo. Tenga en cuenta que esta refspec tiene el indicador de fuerza establecido y trae todas las ramas, todas las etiquetas, todas las ramas de seguimiento remoto y todas las notas. Hay detalles más oscuros sobre qué refspecs se usan cuando, pero usando --tags, con o sin --force, no anula las entradas de configuración (mientras que escribir un conjunto explícito de especificaciones de referencia sí lo hace, por lo que esta es una forma, tal vez la única)--tags difiere de escribir refs/tags/*:refs/tags/*).

Actualizaciones en su propio espacio de referencia (sus propias ramas y etiquetas de seguimiento remoto, generalmente)hacer importa, pero … no para pull, como veremos en la siguiente sección.

git pull

Me gusta decir eso git pull solo corre git fetch seguido de un segundo comando de Git, donde el segundo comando predeterminado es git merge a menos que le indique que use git rebase. Esto es cierto y correcto, pero hay un oscuro detalle en el camino. Esto era más fácil de decir antes git fetch fue reescrito como código C: cuando era un script, se podía seguir el git fetch y git merge comandos y ver cuáles eran los argumentos reales.

Cuando git pull corre bien git merge o git rebase, eso no se usa sus ramas y etiquetas de seguimiento remoto. En su lugar, utiliza los registros que quedan en FETCH_HEAD.

Si examina los ejemplos anteriores, verá que nos dicen que inicialmente, refs/heads/master en el repositorio de git.kernel.org apuntó a comprometerse e05806d.... Después de que corrí git fetch --tags, el nuevo FETCH_HEAD el archivo nos dice que refs/heads/master en el repositorio de git.kernel.org señaló (en el momento en que corrí fetch, puede haber cambiado a estas alturas) para confirmar d7dffce....

Cuando git pull carreras git merge o git rebase, pasa estos números SHA-1 sin procesar. Entonces no importa cual sea tu referencia nombres resolver. los git fetch Corrí, de hecho, actualicé origin/master:

$ git rev-parse origin/master
d7dffce1cebde29a0c4b309a79e4345450bf352a

pero incluso si no lo hubiera hecho, git pull pasaría d7dffce1cebde29a0c4b309a79e4345450bf352a al segundo comando.

Por lo tanto, suponga que está obteniendo etiquetas sin --force y tengo objeto 1234567.... Suponga además que, si hubiera estado obteniendo etiquetas con fuerza, este sería el resultado de git rev-parse refs/tags/last-build, pero porque lo hiciste no usar --force, queda tu propio repositorio last-build apuntando a 8888888... (un compromiso muy afortunado en China :-)). Si usted, personalmente, dice “cuénteme sobre last-build“obtendrás revisión 8888888.... Pero git pull sabe que tiene 1234567... y pase lo que pase, solo pasará el número 1234567... a su segundo comando, si algo así lo requiere.

Una vez más, obtiene ese número de FETCH_HEAD. Entonces, lo que importa aquí es el contenido (completo) de FETCH_HEAD, que se determinan en función de si obtiene con -a / --append, o no. Solo necesitas / quieres --append en casos especiales que no se aplicarán aquí (cuando está obteniendo de múltiples repositorios separados, o obteniendo en pasos separados para propósitos de depuración, o algo así).

Por supuesto, importa más tarde

Si quieres / necesitas tu last-build etiqueta para actualizarse, tendrá que ejecutar git fetch --tags --force en algún momento, y ahora nos metemos en problemas de atomicidad.

Suponga que ha corrido git fetch, con o sin --tags y con o sin --force, quizás corriendo git pull la cual recorre git fetch sin --tags. Ahora te has comprometido 1234567... localmente, y el nombre last-build apunta a cualquiera 8888888... (no actualizado) o 1234567... (actualizado). Ahora tu corres git fetch --tags --force para actualizar todo. Es posible que ahora, el control remoto se ha movido last-build una vez más. Si es así, obtendrá el nuevo valor y actualice su etiqueta local.

Es posible, con esta secuencia, que nunca hayas visto 8888888.... Es posible que tenga una rama que incorpore esa confirmación, pero no sepa la confirmación por esa etiqueta, y ahora que están actualizando sus etiquetas, no lo sabrá 8888888... por esa etiqueta ahora, cualquiera. ¿Eso es bueno, malo o indiferente? Eso depende de usted.

Evitando git pull

Ya que git pull simplemente corre git fetch seguido de un segundo comando, puede ejecutar git fetch usted mismo, seguido del segundo comando. Esto le da un control total sobre el fetch paso y le permite evitar una recuperación redundante.

Desde que tu hacer controlar el fetch paso, puede especificar con precisión, utilizando refspecs, lo que desea actualizar. Ahora es el momento de visitar también el extraño mecanismo de actualización de etiquetas híbridas.

Tome cualquier repositorio que tenga a mano y ejecútelo git ls-remote. Esto te mostrará qué es eso git fetch ve cuando se conecta:

$ git ls-remote | head
From git://git.kernel.org/pub/scm/git/git.git
3313b78c145ba9212272b5318c111cde12bfef4a    HEAD
ad36dc8b4b165bf9eb3576b42a241164e312d48c    refs/heads/maint
3313b78c145ba9212272b5318c111cde12bfef4a    refs/heads/master
af746e49c281f2a2946222252a1effea7c9bcf8b    refs/heads/next
6391604f1412fd6fe047444931335bf92c168008    refs/heads/pu
aa3afa0b4ab4f07e6b36f0712fd58229735afddc    refs/heads/todo
d5aef6e4d58cfe1549adef5b436f3ace984e8c86    refs/tags/gitgui-0.10.0
3d654be48f65545c4d3e35f5d3bbed5489820930    refs/tags/gitgui-0.10.0^{}
33682a5e98adfd8ba4ce0e21363c443bd273eb77    refs/tags/gitgui-0.10.1
729ffa50f75a025935623bfc58d0932c65f7de2f    refs/tags/gitgui-0.10.1^{}

Su Git obtiene, desde el Git remoto, una lista de todas las referencias y sus objetivos. Para las referencias que son etiquetas (anotadas), esto también incluye el objetivo final del objeto de etiqueta: esa es la gitgui-0.10.0^{} aquí. Esta sintaxis representa un pelado etiqueta (ver gitrevisions, aunque no usa la palabra “pelado” aquí).

Su Git luego, por defecto, trae todos los rama—Todo lo que se llama refs/heads/*– preguntando por las confirmaciones a las que apuntan, y las confirmaciones adicionales y otros objetos necesarios para completar esas confirmaciones. (No es necesario que descargue los objetos que ya tiene, solo aquellos que le faltan pero que necesitan). Su Git puede entonces revisar todas las etiquetas peladas para ver si alguna de las etiquetas apunta a una de esas confirmaciones. Si es así, su Git toma, con o sin --force modo, dependiendo de su recuperación, la etiqueta dada. Si esa etiqueta apunta a un objeto de etiqueta, en lugar de directamente a una confirmación, su Git también agrega ese objeto de etiqueta a la colección.

En las versiones de Git anteriores a la 1.8.2, Git aplica por error las reglas de la rama a empujado actualizaciones de etiquetas: están permitidas sin --force siempre que el resultado sea un avance rápido. Es decir, el destino de la etiqueta anterior simplemente tendría que ser un antepasado del nuevo destino de la etiqueta. Esto solo afecta a las etiquetas ligeras, obviamente, y en cualquier caso, las versiones 1.8.2 y superiores de Git “nunca reemplazan una etiqueta sin --force“comportamiento en empujar. Sin embargo, el comportamiento observado para Git 2.10.xy 2.11.x es que las etiquetas se reemplazan al buscar, cuando se usan --tags.

Pero pase lo que pase, si su objetivo es actualizar todas las etiquetas a la fuerza y todas las sucursales de seguimiento remoto de la forma habitual, git fetch --tags --force --prune lo haré; o tu puedes git fetch --prune '+refs/tags/*:refs/tags/*' '+refs/heads/*:refs/remotes/origin/*', que usa el + sintaxis para forzar tanto la etiqueta como las actualizaciones de rama de seguimiento remoto. (Los --prune es opcional como de costumbre). mayo ser innecesario, pero al menos inofensivo aquí, y podría hacer algo útil en algunas versiones de Git. Y ahora que sus etiquetas y sucursales de seguimiento remoto están actualizadas, puede usar git merge o git rebase sin argumentos en absoluto, para fusionar o rebasar usando la rama actual configurada en sentido ascendente. Puede repetir esto para tantas ramas como desee, sin necesidad de ejecutar git pull (con su redundante fetch) en absoluto.

Respecto al pedido: cualquier pedido funciona (conmuta).


Una nota sobre los comandos que ejecuta:

  • git fetch --tags ya “forzará la actualización” de sus etiquetas locales
  • los --force La opción solo se aplica a las especificaciones de referencia que no comienzan con + opción
  • git pull --tags origin mybranch aplicará todo lo que desee de una sola vez (obtenga todas las etiquetas y actualice su sucursal local)
¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *