'git pull origin mybranch' deixa os commits mybranch N locais antes da origem. Por quê?

92

Acabei de observar algo estranho git pull, que não entendo.

Na sexta-feira, trabalhei em uma filial local. vamos chamá-lo mybranch. Antes de deixar o escritório Empurrei-a origem (que é o meu github repo): git push origin mybranch.

Ontem em casa, pullmudei meubranch para meu laptop, fiz mais alguma codificação e, em seguida, empurrei minhas alterações de volta para o github (origem).

Agora estou no trabalho novamente e tentei puxar as alterações de ontem para minha máquina de trabalho (não mudei nada no repositório local do meu local de trabalho no fim de semana):

git pull origin mybranch

que causou uma fusão de avanço rápido, o que é bom. Então eu fiz um git status, e ele disse:

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

Hã? Como pode ser 6 commits à frente quando eu nem toquei no fim de semana, E apenas puxei da origem? Então eu rodei um git diff origin/mybranche os diffs eram exatamente as 6 alterações que acabei de extrair do controle remoto.

Eu só poderia "consertar" isso executando git fetch origin:

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

Aparentemente, meu repositório local estava faltando alguns objetos de referência, mas como pode ser isso? Quer dizer, um pull já faz uma busca, e eu não trabalhei em nada exceto naquele branch, então a git fetch origine git fetch origin mybranchdeveria ter o mesmo resultado?

Devo sempre usar em git pull originvez de git pull origin branchname?

Estou confuso.

Matthias
fonte
Eu também percebi isso; a git pushtambém parecerá resolvê-lo (relatando "tudo atualizado").
Ben James
4
git config --get-regexp br.*pode dizer se sua configuração tem um branch local está rastreando outro branch
VonC
3
Você pode digitar git config branch.master.remote yourGitHubRepo.gitseu workRepo e verificar (a seguir git pull origin) se o status permanece com um aviso 'em frente'?
VonC
não está definido (saída vazia). mas git remote show originme mostra que a origem aponta para meu repositório GitHub, então deve estar tudo bem, eu acho?
Matias
1
Git remote sozinho (mostrando o endereço correto para o repositório GitHub) não é suficiente . Para evitar a exibição de uma Your branch is aheadmensagem de aviso " " após um git pull, você precisa primeiro definir também o nome remoto de uma ramificação . Daí minha sugestão: digite git config branch.master.remote yourGitHubRepo.git, tente a git pulle a git statuse veja se o problema persiste.
VonC

Respostas:

115

git pullchamadas git fetchcom os parâmetros apropriados antes de mesclar os cabeçotes buscados explicitamente (ou, se nenhum, o branch remoto configurado para mesclar) no branch atual.

A sintaxe: git fetch <repository> <ref>onde <ref>é apenas um nome de ramificação sem dois-pontos é uma busca 'única' que não faz uma busca padrão de todas as ramificações rastreadas do controle remoto especificado, mas, em vez disso, busca apenas a ramificação nomeada FETCH_HEAD.

Atualização: para versões do Git desde 1.8.4, se houver um branch de rastreamento remoto que rastreia o ref que você pediu para buscar, o branch de rastreamento agora será atualizado por fetch. Essa alteração foi feita especificamente para evitar a confusão que o comportamento anterior causou.

Quando você executa git pull <repository> <ref>, FETCH_HEADé atualizado como acima, em seguida, mesclado em seu check-out, HEADmas nenhum dos branches de rastreamento padrão para o repositório remoto será atualizado (Git <1.8.4). Isso significa que localmente parece que você está à frente do branch remoto, mas na verdade você está atualizado com ele.

Pessoalmente, sempre faço git fetchseguido por git merge <remote>/<branch>porque vejo quaisquer avisos sobre atualizações forçadas antes de mesclar e posso visualizar o que estou mesclando. Se eu usasse git pullum pouco mais do que faço, faria um simples git pullsem parâmetros a maioria do tempo, contando com branch.<branch>.remotee branch.<branch>.mergepara 'fazer a coisa certa'.

CB Bailey
fonte
4
+1 Essa é realmente uma boa explicação! Eu sabia que a explicação estava escondida em algum lugar dentro de 'git help fetch', mas não consegui tirá-la ...
Stefan Näwe
1
+1. Boa postagem, com uma abordagem semelhante a gitster.livejournal.com/28309.html
VonC
1
Então, um git fetchafter a git pull <repository> <ref>corrigiria o problema, uma vez que a busca atualizaria os branches de rastreamento padrão? Além disso, obrigado por esta resposta, começando a fazer sentido :)
Bart Jedrocha
1
Também encontrei esse problema e você precisa fazer o git fetchseguido por git merge origin/master master.
user1027169
3

O que git remote -v showretorna quando se trata de origem?

Se a origem apontar para o github, o status deve ser atualizado e não antes de qualquer repo remoto. Pelo menos, com o Git1.6.5 estou usando para um teste rápido.

De qualquer forma, para evitar isso, defina explicitamente o repo remoto do branch master:

$ git config branch.master.remote yourGitHubRepo.git

em seguida git pull origin master, a , seguido por a, git statusdeve retornar um status limpo (sem à frente).
Por quê? porque o get fetch origin master (incluído no git pull origin master) não apenas atualizaria FETCH_HEAD(como Charles Bailey explica em sua resposta ), mas também atualizaria o "branch master remoto" dentro do seu repositório Git local.
Nesse caso, seu mestre local não pareceria mais estar "à frente" do mestre remoto.


Posso testar isso, com um git1.6.5:

Primeiro eu crio um 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"

Eu simulo um repositório GitHub criando um repositório simples (que pode receber push de qualquer lugar)

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

Eu adiciono um modif ao meu repo de trabalho, que empurro para o repo do github (adicionado como um 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

Eu crio um repositório doméstico, clonado do GitHub, no qual faço algumas modificações, enviadas ao 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

Eu então clono o workrepo para um primeiro 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(-)

Nesse repo, git status menciona master geing antes de ' 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)

Mas isso só originnão é 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)

Mas se eu repetir a sequência em um repo que tem uma origem no github (ou nenhuma origem, apenas um 'github' remoto definido), o status é limpo:

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)

Se eu tivesse apenas originapontando github, statusestaria limpo para git1.6.5.
Pode ser com um aviso 'à frente' para o git anterior, mas de qualquer maneira, um git config branch.master.remote yourGitHubRepo.gitdefinido explicitamente deve ser capaz de cuidar disso, mesmo com as primeiras versões do Git.

VonC
fonte
Obrigado por dedicar seu tempo para analisar isso. O remoto de origem já aponta para meu repositório GitHub. Clonei esse projeto de um url do GitHub e meu branch master local está rastreando origin / master. Quanto ao meu ramo, tenho quase certeza de que o criei a partir do ramo origin / mybranch, que deve rastreá-lo automaticamente. Mas ainda assim, talvez seja este o problema? Que o mybranch local não rastreia realmente a origem / mybranch? PS: Estou usando o git 1.6.1 (via MacPorts).
Matthias
Existe um comando git que me permite ver se um branch local está rastreando outro branch? Não consigo encontrar nas páginas de manual.
Matthias
Você pode ver com quais ramos remotos são rastreados git remote show origin.
Ted Percival
2

Você tem o cuidado de adicionar todo o seu controle remoto (exceto o originque vem com o seu clone original) usando git remote add NAME URL? Eu vi esse bug quando eles acabaram de ser adicionados à configuração do git.

Pat Notz
fonte
Fiz isso ao clonar o repo. Não fiz isso com cada ramo, no entanto. Por exemplo, meu ramo eu primeiro buscaria na origem, então git checkout -b mybranch origin/mybranch. De acordo com a página de manual do git-branch, a origem / mybranch é o ponto de início e, além disso, afirma para --track: "... Use isto se você sempre puxar do mesmo branch upstream para o novo branch, e se você não quiser usar "git pull <repository> <refspec>" explicitamente. Este comportamento é o padrão quando o ponto de início é um branch remoto. "
Matias