'git pull origin mybranch' deja las confirmaciones locales de mybranch N antes del origen. ¿Por qué?

92

Acabo de observar algo extraño git pullque no entiendo.

El viernes trabajé en una sucursal local. llamémoslo mybranch. Antes de salir de la oficina empujé con el origen (que es mi github repo): git push origin mybranch.

Ayer en casa, pulledité mybranch en mi computadora portátil, hice un poco más de codificación y luego empujé mis cambios a github (origen).

Ahora estoy en el trabajo de nuevo e intenté llevar los cambios de ayer a mi máquina de trabajo (no cambié nada en el repositorio local de mi lugar de trabajo durante el fin de semana):

git pull origin mybranch

que provocó una fusión de avance rápido, lo cual está bien. Luego hice una git status, y dijo:

# On branch mybranch
# Your branch is ahead of 'origin/mybranch' by 6 commits.
#
nothing to commit (working directory clean)

¿Eh? ¿Cómo pueden ser 6 confirmaciones por delante cuando ni siquiera lo toqué durante el fin de semana, Y simplemente lo saqué del origen? Entonces ejecuté a git diff origin/mybranchy las diferencias fueron exactamente los 6 cambios que acabo de extraer del control remoto.

Solo pude "arreglar" esto ejecutando git fetch origin:

From [email protected]:me/project
af8be00..88b0738  mybranch -> origin/mybranch

Aparentemente, a mi repositorio local le faltaban algunos objetos de referencia, pero ¿cómo puede ser eso? Quiero decir, un tirón ya hace una búsqueda, y no trabajé en nada excepto en esa rama, por lo que un git fetch originy git fetch origin mybranchdebería tener el mismo resultado.

¿Debería usar siempre en git pull originlugar de git pull origin branchname?

Estoy confundido.

Matías
fuente
Yo también me di cuenta de esto; a git pushtambién parecerá resolverlo (reportando "todo actualizado").
Ben James
4
git config --get-regexp br.*puede decirle si su configuración tiene una sucursal local que está rastreando otra sucursal
VonC
3
¿Puede escribir git config branch.master.remote yourGitHubRepo.gitsu workRepo y verificar (en el siguiente git pull origin) si el estado permanece con una advertencia de 'adelantado'?
VonC
no está configurado (salida vacía). pero git remote show originme muestra que el origen apunta a mi repositorio de GitHub, así que supongo que debería estar bien.
Matthias
1
git remote solo (mostrando la dirección correcta para el repositorio de GitHub) no es suficiente . Para evitar tener un " Your branch is ahead" mensaje de advertencia después de un git pull, primero debe definir también el nombre remoto de una rama . De ahí mi sugerencia: escriba git config branch.master.remote yourGitHubRepo.git, luego intente ay git pulla git statusy vea si el problema persiste.
VonC

Respuestas:

115

git pullllamadas git fetchcon los parámetros apropiados antes de fusionar los encabezados obtenidos explícitamente (o si ninguno, la rama remota configurada para fusionarse) en la rama actual.

La sintaxis: git fetch <repository> <ref>donde <ref>es solo un nombre de rama sin dos puntos es una búsqueda de 'una sola vez' que no realiza una búsqueda estándar de todas las ramas rastreadas del control remoto especificado, sino que solo obtiene la rama nombrada FETCH_HEAD.

Actualización: para las versiones de Git desde 1.8.4, si hay una rama de seguimiento remoto que rastrea la referencia que solicitó buscar, la rama de seguimiento ahora se actualizará por fetch. Este cambio se ha realizado específicamente para evitar la confusión que provocó el comportamiento anterior.

Cuando lo realiza git pull <repository> <ref>, FETCH_HEADse actualiza como se indicó anteriormente, luego se fusiona con su desprotegido, HEADpero ninguna de las ramas de seguimiento estándar para el repositorio remoto se actualizará (Git <1.8.4). Esto significa que, localmente, parece que está por delante de la rama remota, mientras que de hecho está al día con ella.

Personalmente, siempre lo hago git fetchseguido de git merge <remote>/<branch>porque veo cualquier advertencia sobre actualizaciones forzadas antes de fusionarme, y puedo obtener una vista previa de lo que estoy fusionando. Si usara git pullun poco más de lo que hago, haría un simple git pullsin parámetros la mayoría del tiempo, confiar branch.<branch>.remotey branch.<branch>.merge"hacer lo correcto".

CB Bailey
fuente
4
+1 ¡Esa es realmente una buena explicación! Sabía que la explicación se escondía en algún lugar dentro de 'git help fetch' pero no podía sacarla ...
Stefan Näwe
1
+1. Buena publicación, con un enfoque similar a gitster.livejournal.com/28309.html
VonC
1
Lo mismo sucedería con una git fetchdespués de una git pull <repository> <ref>solución al problema ya que la zona de alcance actualizaría las ramas de seguimiento estándar? Además, gracias por esta respuesta, que empieza a tener sentido :)
Bart Jedrocha
1
También me encontré con este problema y tendrías que git fetchseguir adelante git merge origin/master master.
user1027169
3

¿Qué git remote -v showdevuelve cuando se trata de origen?

Si el origen apunta a github, el estado debe estar actualizado y no antes que ningún repositorio remoto. Al menos, con el Git1.6.5 que estoy usando para una prueba rápida.

De todos modos, para evitar esto, defina explícitamente el repositorio remoto de la rama maestra:

$ git config branch.master.remote yourGitHubRepo.git

luego a git pull origin master, seguido de a git statusdebería devolver un estado limpio (no adelante).
¿Por qué? porque el get fetch origin master (incluido en el git pull origin master) no solo se actualizaría FETCH_HEAD(como explica Charles Bailey en su respuesta ), sino que también actualizaría la "rama maestra remota" dentro de su repositorio local de Git.
En ese caso, su maestro local ya no parecería estar "por delante" del maestro remoto.


Puedo probar esto, con un git1.6.5:

Primero creo un workrepo:

PS D:\git\tests> cd pullahead
PS D:\git\tests\pullahead> git init workrepo
Initialized empty Git repository in D:/git/tests/pullahead/workrepo/.git/
PS D:\git\tests\pullahead> cd workrepo
PS D:\git\tests\pullahead\workrepo> echo firstContent > afile.txt
PS D:\git\tests\pullahead\workrepo> git add -A 
PS D:\git\tests\pullahead\workrepo> git commit -m "first commit"

Simulo un repositorio de GitHub creando un repositorio simple (uno que puede recibir push desde cualquier lugar)

PS D:\git\tests\pullahead\workrepo> cd ..
PS D:\git\tests\pullahead> git clone --bare workrepo github

Agrego un modif a mi repositorio de trabajo, que empujo al repositorio de github (agregado como un control remoto)

PS D:\git\tests\pullahead> cd workrepo
PS D:\git\tests\pullahead\workrepo> echo aModif >> afile.txt
PS D:\git\tests\pullahead\workrepo> git ci -a -m "a modif to send to github"
PS D:\git\tests\pullahead\workrepo> git remote add github d:/git/tests/pullahead/github
PS D:\git\tests\pullahead\workrepo> git push github

Creo un repositorio de inicio, clonado de GitHub, en el que hago un par de modificaciones, enviadas a GitHub:

PS D:\git\tests\pullahead\workrepo> cd ..
PS D:\git\tests\pullahead> git clone github homerepo
PS D:\git\tests\pullahead> cd homerepo
PS D:\git\tests\pullahead\homerepo> type afile.txt
firstContent
aModif

PS D:\git\tests\pullahead\homerepo> echo aHomeModif1  >> afile.txt
PS D:\git\tests\pullahead\homerepo> git ci -a -m "a first home modif"
PS D:\git\tests\pullahead\homerepo> echo aHomeModif2  >> afile.txt
PS D:\git\tests\pullahead\homerepo> git ci -a -m "a second home modif"
PS D:\git\tests\pullahead\homerepo> git push github

Luego clono workrepo para un primer experimento

PS D:\git\tests\pullahead\workrepo4> cd ..
PS D:\git\tests\pullahead> git clone workrepo workrepo2
Initialized empty Git repository in D:/git/tests/pullahead/workrepo2/.git/
PS D:\git\tests\pullahead> cd workrepo2
PS D:\git\tests\pullahead\workrepo2> git remote add github d:/git/tests/pullahead/github
PS D:\git\tests\pullahead\workrepo2> git pull github master
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From d:/git/tests/pullahead/github
 * branch            master     -> FETCH_HEAD
Updating c2763f2..75ad279
Fast forward
 afile.txt |  Bin 46 -> 98 bytes
 1 files changed, 0 insertions(+), 0 deletions(-)

En ese repositorio, git status menciona que el maestro se adelanta a ' origin':

PS D:\git\tests\pullahead\workrepo5> git status
# On branch master
# Your branch is ahead of 'origin/master' by 2 commits.
#
nothing to commit (working directory clean)

Pero eso es solo originque no es github:

PS D:\git\tests\pullahead\workrepo2> git remote -v show
github  d:/git/tests/pullahead/github (fetch)
github  d:/git/tests/pullahead/github (push)
origin  D:/git/tests/pullahead/workrepo (fetch)
origin  D:/git/tests/pullahead/workrepo (push)

Pero si repito la secuencia en un repositorio que tiene un origen en github (o no tiene ningún origen, solo un 'github' remoto definido), el estado es limpio:

PS D:\git\tests\pullahead\workrepo2> cd ..
PS D:\git\tests\pullahead> git clone workrepo workrepo4
PS D:\git\tests\pullahead> cd workrepo4
PS D:\git\tests\pullahead\workrepo4> git remote rm origin
PS D:\git\tests\pullahead\workrepo4> git remote add github d:/git/tests/pullahead/github
PS D:\git\tests\pullahead\workrepo4> git pull github master
remote: Counting objects: 8, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 6 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (6/6), done.
From d:/git/tests/pullahead/github
 * branch            master     -> FETCH_HEAD
Updating c2763f2..75ad279
Fast forward
 afile.txt |  Bin 46 -> 98 bytes
 1 files changed, 0 insertions(+), 0 deletions(-)
PS D:\git\tests\pullahead\workrepo4> git status
# On branch master
nothing to commit (working directory clean)

Si solo hubiera originapuntado github, statusestaría limpio para git1.6.5.
Puede ser con una advertencia 'por adelantado' para git anteriores, pero de todos modos, un git config branch.master.remote yourGitHubRepo.gitdefinido explícitamente debería poder encargarse de eso, incluso con versiones anteriores de Git.

VonC
fuente
Gracias por tomarse el tiempo para investigar esto. El control remoto de origen ya apunta a mi repositorio de GitHub. Cloné ese proyecto desde una URL de GitHub y mi rama maestra local está rastreando el origen / maestro. En cuanto a mybranch, estoy bastante seguro de que lo creé a partir de la rama origin / mybranch, que debería rastrearlo automáticamente. Pero aún así, ¿quizás este es el problema? ¿Que el mybranch local en realidad no rastrea el origen / mybranch? PD: estoy usando git 1.6.1 (a través de MacPorts).
Matthias
¿Hay un comando git que me permita ver si una sucursal local está rastreando otra sucursal? No puedo encontrarlo en las páginas de manual.
Matthias
Puede ver con qué ramas remotas se realiza el seguimiento git remote show origin.
Ted Percival
2

¿Tiene cuidado de agregar todo su control remoto (excepto el originque viene con su clon original) usando git remote add NAME URL? He visto este error cuando se acaban de agregar a la configuración de git.

Pat Notz
fuente
Hice esto al clonar el repositorio. Sin embargo, no hice esto con cada rama. Por ejemplo, mybranch primero buscaría desde el origen, luego git checkout -b mybranch origin/mybranch. De acuerdo con la página de manual de git-branch, el origen / mybranch es el punto de inicio y, además, indica para --track: "... Use esto si siempre extrae de la misma rama ascendente a la nueva rama, y si no desea utilizar "git pull <repository> <refspec>" explícitamente. Este comportamiento es el predeterminado cuando el punto de inicio es una rama remota ".
Matthias