2009-11-16 7 views
91

Ho appena osservato qualcosa di strano su git pull, che non capisco.'git pull origin mybranch' lascia locale mybranch N commette prima dell'origine. Perché?

Venerdì ho lavorato in una filiale locale. chiamiamolo mybranch. Prima di lasciare l'ufficio l'ho spinto all'origine (che è il mio repository Github): git push origin mybranch.

Ieri a casa, I pull e mybranch sul mio portatile, ho fatto un po 'di codifica e poi ho trasferito le mie modifiche a github (origine).

Ora sono di nuovo al lavoro, e ho cercato di tirare le modifiche di ieri alla mia macchina di lavoro (Non ho cambiato nulla nella repo locale del mio posto di lavoro durante il fine settimana):

git pull origin mybranch 

che ha causato un'unione avanti veloce, che va bene. Poi ho fatto un git status, e ha detto:

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

Eh? Come può essere 6 avanti quando non l'ho nemmeno toccato durante il weekend, E appena estratto dall'origine? Così ho eseguito un git diff origin/mybranch e le differenze erano esattamente le 6 modifiche che ho appena estratto da remoto.

Potevo solo "fissare" eseguendo git fetch origin:

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

A quanto pare, il mio repo locale mancava alcuni oggetti di riferimento, ma come può essere? Voglio dire, un pull lo fa già, e non ho funzionato su nulla tranne quel ramo, quindi uno git fetch origin e git fetch origin mybranch dovrebbe avere lo stesso risultato?

Devo usare sempre git pull origin invece di git pull origin branchname?

Sono confuso.

+0

Ho notato anche questo; anche un 'git push' sembra risolverlo (riportando" tutto aggiornato "). –

+4

'git config --get-regexp br. *' Può dirti se la tua configurazione ha un ramo locale sta monitorando un altro ramo – VonC

+3

Puoi digitare 'git config branch.master.remote yourGitHubRepo.git' nel tuo workRepo e controllare (a il prossimo 'git pull origin') se lo stato rimane con un avviso 'avanti'? – VonC

risposta

113

git pull chiamate git fetch con i parametri appropriati prima di unire le testine esplicitamente scaricate (o se nessuna delle diramazioni remote configurate per l'unione) nel ramo corrente.

La sintassi: git fetch <repository> <ref> dove <ref> è solo un nome ramo senza i due punti è un 'one shot' recuperare che non fa uno standard recuperare di tutti i rami tracciati del remoto specificato ma invece recupera solo il ramo denominato in FETCH_HEAD.

Aggiornamento: per le versioni Git 1.8.4 in quanto, se non v'è una filiale di monitoraggio remoto che segue l'arbitro che hai chiesto di andare a prendere poi il ramo di monitoraggio sarà ora aggiornato da fetch. Questo cambiamento è stato fatto appositamente per evitare la confusione causata dal comportamento precedente.

Quando si esegue git pull <repository> <ref>, FETCH_HEAD è aggiornato come sopra, poi fusa nel vostro estratto HEAD ma nessuno dei rami di tracciamento standard per il repository remoto sarà aggiornato (Git < 1.8.4).Ciò significa che localmente lo sembra come se fosse prima del ramo remoto, mentre in realtà sei aggiornato con esso.

Personalmente faccio sempre git fetch seguito da git merge <remote>/<branch> perché riesco a vedere eventuali avvisi di aggiornamenti forzati prima di unire, e posso vedere in anteprima quello che sto fondendo. Se ho usato git pull un po 'più di me, lo farei fare un semplice git pull senza parametri la maggior parte del tempo, basandosi su branch.<branch>.remote e branch.<branch>.merge per 'fare la cosa giusta'.

+4

+1 Questa è davvero una buona spiegazione! Sapevo che la spiegazione si nascondeva da qualche parte all'interno di 'git help fetch' ma non riuscivo a capirlo ... –

+1

+1. Buon post, con un approccio simile a http://gitster.livejournal.com/28309.html – VonC

+1

Quindi un 'git fetch' dopo un' git pull 'risolve il problema dal momento che il recupero aggiornerebbe i rami di tracciamento standard? Inoltre, grazie per questa risposta, cominciando a dare un senso :) –

3

Cosa restituisce git remote -v show quando si tratta di origine?

Se l'origine punta a github, lo stato deve essere aggiornato e non in anticipo rispetto a qualsiasi repository remoto. Almeno, con il Git1.6.5 che sto usando per un test rapido.

In ogni caso, per evitare questo, definire in modo esplicito il repo remoto del ramo principale:

$ git config branch.master.remote yourGitHubRepo.git 

poi un git pull origin master, seguito da un git status dovrebbe restituire uno stato pulito (non avanti).
Perché? poiché il master get get get (incluso nel generatore di origine git pull) non aggiornerebbe solo FETCH_HEAD (come Charles Bailey spiega come his answer), ma sarebbe anche aggiornare il "ramo master remoto" nel repository Git locale.
In tal caso, il tuo master locale non sembrerebbe più "avanti" del master remoto.


Posso testare questo, con un git1.6.5:

prima cosa creare 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" 

ho simulare un repo GitHub con la creazione di un pronti contro termine nudo (uno che può ricevere spinta da qualsiasi luogo)

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

aggiungo un modif a il mio repo di lavoro, che mi spingono a github pronti contro termine (aggiunto come un telecomando)

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 repo casa, o clonato f GitHub, in cui faccio un paio di modifiche, spinto al 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 

Ho poi clonare workrepo per un primo esperimento

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(-) 

In questo repo, git status fa menzione padrone geing anticipo '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) 

Ma questa è solo origin non è 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) 

Ma se ripeto la sequenza in un repo, che ha un'origine a github (o nessuna origine a tutti, solo un 'github' a distanza definita), lo stato è pulito:

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 dovessi solo origin che punta su github, status sarebbe pulito per git1.6.5.
Potrebbe essere con un avviso "avanti" per il git precedente, ma in ogni caso, una definizione esplicita di git config branch.master.remote yourGitHubRepo.git dovrebbe essere in grado di occuparsene, anche con le versioni precedenti di Git.

+0

Grazie per aver dedicato del tempo per esaminare questo. Il telecomando di origine punta già al mio repository GitHub. Ho clonato quel progetto da un url GitHub e il mio ramo master locale sta monitorando l'origine/master. Per quanto riguarda il mybranch, sono abbastanza sicuro di averlo creato dal ramo origin/mybranch, che dovrebbe tracciarlo automaticamente. Ma ancora, forse questo è il problema? Che il mybranch locale in realtà non tiene traccia dell'origine/mybranch? PS: sto usando git 1.6.1 (via MacPorts). – Matthias

+0

Esiste un comando git che mi consente di vedere se un ramo locale sta monitorando un altro ramo? Non riesco a trovarlo nelle pagine man. – Matthias

+0

Puoi vedere quali rami remoti sono tracciati con 'git remote show origin'. –

2

Stai attento a aggiungere tutto il tuo telecomando (eccetto lo origin fornito con il tuo clone originale) usando git remote add NAME URL? Ho visto questo bug quando sono stati appena aggiunti a git config.

+0

L'ho fatto quando ho clonato il repository. Non ho fatto questo con ogni ramo, tuttavia. Ad es. mybranch dovrei prima recuperare dall'origine, quindi 'git checkout -b mybranch origin/mybranch'. Secondo la pagina man di git-branch, origin/mybranch è il punto di partenza, e inoltre indica --track: "... Usa questo se si tira sempre dallo stesso ramo upstream nel nuovo ramo, e se non si desidera utilizzare "git pull " in modo esplicito, questo comportamento è l'impostazione predefinita quando il punto di partenza è un ramo remoto. " – Matthias

Problemi correlati