'Git Pull Origin Mybranch' deixa o MyBranch N se compromete à frente da origem. Por quê?
-
20-09-2019 - |
Pergunta
Acabei de observar algo estranho sobre git pull
, o que eu não entendo.
Na sexta -feira, trabalhei em uma filial local. Vamos chamá -lo mybranch
. Antes de sair do escritório, empurrei -o para a origem (que é o meu repo Github): git push origin mybranch
.
Ontem em casa, eu pull
Ed Mybranch para o meu laptop, fez mais codificação e depois empurrou minhas alterações de volta ao Github (origem).
Agora estou no trabalho novamente e tentei puxar as mudanças 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
Isso causou uma mesclagem rápida, o que é bom. Eu então fiz um git status
, e disse:
# On branch mybranch
# Your branch is ahead of 'origin/mybranch' by 6 commits.
#
nothing to commit (working directory clean)
Huh? Como pode ser 6 começos à frente quando eu nem tocei no fim de semana e acabou de sair da origem? Então eu corri um git diff origin/mybranch
E os diferenciais foram exatamente as 6 alterações que acabei de retirar do controle remoto.
Eu só poderia "consertar" isso correndo git fetch origin
:
From git@github.com:me/project
af8be00..88b0738 mybranch -> origin/mybranch
Aparentemente, meu repositório local estava faltando alguns objetos de referência, mas como isso pode ser? Quero dizer, uma atração já faz uma busca, e eu não trabalhei em nada, exceto naquele ramo, então um git fetch origin
e git fetch origin mybranch
deve ter o mesmo resultado?
Devo sempre usar git pull origin
ao invés de git pull origin branchname
?
Estou confuso.
Solução
git pull
chamadas git fetch
com os parâmetros apropriados antes de mesclar as cabeças explicitamente buscadas (ou se nenhuma a ramificação remota configurada para mesclar) na ramificação atual.
A sintaxe: git fetch <repository> <ref>
Onde <ref>
é apenas um nome de ramo sem cólon é uma busca de 'tiro' que não faz uma busca padrão de todos os galhos rastreados do controle remoto especificado, mas, em vez disso, pega apenas o ramo nomeado em FETCH_HEAD
.
Atualizar: Para versões Git desde 1.8.4, se houver uma filial de rastreamento remoto que rastreie o árbitro que você pediu para buscar, o ramo de rastreamento será atualizado agora por fetch
. Essa mudança foi feita especificamente para evitar a confusão que o comportamento anterior causou.
Quando você se apresenta git pull <repository> <ref>
, FETCH_HEAD
é atualizado como acima e depois fundido no seu check -out HEAD
Mas nenhuma das filiais de rastreamento padrão para o repositório remoto será atualizada (git <1.8.4). Isso significa que localmente parece Como você está à frente do ramo remoto, enquanto na verdade você está atualizado com ela.
Pessoalmente eu sempre faço git fetch
Seguido por git merge <remote>/<branch>
Porque eu consigo ver quaisquer avisos sobre atualizações forçadas antes de me fundir, e posso visualizar o que estou se fundindo. Se eu usasse git pull
um pouco mais do que eu, eu faria uma planície git pull
sem parâmetros na maioria das vezes, confiando branch.<branch>.remote
e branch.<branch>.merge
para 'fazer a coisa certa'.
Outras dicas
O que git remote -v show
retorna quando se trata de origem?
Se a origem apontar para o GitHub, o status deve estar 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 repositório remoto do Master Branch:
$ git config branch.master.remote yourGitHubRepo.git
então uma git pull origin master
, seguido por um git status
deve retornar um status limpo (sem a frente).
Por quê? Porque o mestre de origem get fetch (incluído no mestre de origem do git) não apenas atualizaria FETCH_HEAD
(Como Charles Bailey explica em sua resposta), mas isso também Atualize a "ramificação mestre remota" no seu repositório Git local.
Nesse caso, seu mestre local não parece mais "à frente" do mestre remoto.
Eu 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 simula um repo do github criando um repo nu (que pode receber um empurrão de qualquer lugar)
PS D:\git\tests\pullahead\workrepo> cd ..
PS D:\git\tests\pullahead> git clone --bare workrepo github
Adicionei um modif ao meu repositório de trabalho, que pressiono para o repo do GitHub (adicionado como um controle 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 de github, no qual faço algumas modificações, empurrado para o 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 clono entã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 repositório, o status do Git menciona o mestre geing à frente 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 é apenas origin
nã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 repositório 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 origin
apontando github
, status
Seria 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.git
definido explicitamente deve ser capaz de cuidar disso, mesmo com versões iniciais do Git.
Você tem o cuidado de adicionar todo o seu controle remoto (exceto origin
que vem com seu clone original) usando git remote add NAME URL
? Eu já vi esse bug quando eles acabaram de ser adicionados à configuração do Git.