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)