'git pull origin mybranch' lascia il mybranch locale N commit prima dell'origine. Perché?


92

Ho appena osservato qualcosa di strano git pull, che non capisco.

Venerdì ho lavorato in una filiale locale. chiamiamolo mybranch. Prima di lasciare l'ufficio ho spinto per provenienza (che è il mio github repo): git push origin mybranch.

Ieri a casa, ho pulltrasferito il mio ramo al mio laptop, ho fatto ancora un po 'di codifica e poi ho rimandato le mie modifiche a github (origin).

Ora sono di nuovo al lavoro e ho provato a trasferire le modifiche di ieri alla mia macchina da lavoro (non ho cambiato nulla nel repository locale del mio posto di lavoro durante il fine settimana):

git pull origin mybranch

che ha causato un'unione in 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 possono essere 6 commit in avanti se non l'ho nemmeno toccato durante il fine settimana e ho appena tirato fuori dall'origine? Quindi ho eseguito un git diff origin/mybranche le differenze erano esattamente le 6 modifiche che ho appena eseguito dal telecomando.

Potrei solo "aggiustarlo" eseguendo git fetch origin:

From git@github.com:me/project
af8be00..88b0738  mybranch -> origin/mybranch

Apparentemente, nel mio repository locale mancavano alcuni oggetti di riferimento, ma come può essere? Voglio dire, un pull fa già un fetch, e non ho lavorato su niente tranne quel ramo, quindi a git fetch origine git fetch origin mybranchdovrebbe avere lo stesso risultato?

Dovrei sempre usare al git pull originposto di git pull origin branchname?

Non ho capito bene.


L'ho notato anche io; una git pushsarà anche sembrare di risolverlo (reporting "tutti aggiornati").
Ben James,

4
git config --get-regexp br.*può dirti se la tua configurazione ha un ramo locale che sta monitorando un altro ramo
VonC

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

non è impostato (output vuoto). ma git remote show originmi mostra che origin punta al mio repository GitHub, quindi dovrebbe andare bene immagino?
Matthias

1
git remote da solo (che mostra l'indirizzo giusto per il repository GitHub) non è sufficiente . Per evitare di visualizzare un Your branch is aheadmessaggio di avviso dopo " " git pull, è necessario prima definire anche il nome remoto per un ramo . Da qui il mio suggerimento: digita git config branch.master.remote yourGitHubRepo.git, quindi prova a git pulle a git statuse vedi se il problema persiste.
VonC

Risposte:


115

git pullchiama git fetchcon i parametri appropriati prima di unire le teste caricate in modo esplicito (o, se nessuna, il ramo remoto configurato per l'unione) nel ramo corrente.

La sintassi: git fetch <repository> <ref>dove <ref>è solo un nome di ramo senza due punti è un recupero "one shot" che non esegue un recupero standard di tutti i rami tracciati del telecomando specificato ma recupera solo il ramo denominato in FETCH_HEAD.

Aggiornamento: per le versioni di Git dalla 1.8.4, se è presente un ramo di tracciamento remoto che tiene traccia del riferimento che hai chiesto di recuperare, il ramo di tracciamento verrà ora aggiornato da fetch. Questa modifica è stata apportata specificamente per evitare la confusione causata dal comportamento precedente.

Quando esegui git pull <repository> <ref>, FETCH_HEADviene aggiornato come sopra, quindi unito al tuo estratto HEADma nessuno dei rami di tracciamento standard per il repository remoto verrà aggiornato (Git <1.8.4). Ciò significa che localmente sembra che tu sia in anticipo rispetto al ramo remoto, mentre in realtà sei aggiornato con esso.

Personalmente lo faccio sempre git fetchseguito da git merge <remote>/<branch>perché riesco a vedere eventuali avvisi sugli aggiornamenti forzati prima di unirli, e posso vedere in anteprima cosa sto unendo. Se usassi git pullun po 'più di me, farei un semplice git pullsenza parametri del tempo, fare affidamento su branch.<branch>.remotee branch.<branch>.merge"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
tirarla

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

1
Quindi un git fetchdopo a git pull <repository> <ref>risolvere il problema poiché il recupero aggiorna i rami di tracciamento standard? Inoltre, grazie per questa risposta, che inizia ad avere un senso :)
Bart Jedrocha

1
Mi sono imbattuto anche in questo problema e dovresti farlo git fetchseguito da git merge origin/master master.
user1027169

3

Cosa git remote -v showrestituisce quando si parla di origine?

Se origin punta a GitHub, lo stato dovrebbe essere aggiornato e non prima di qualsiasi repository remoto. Almeno, con Git1.6.5 che sto usando per un rapido test.

Comunque, per evitare questo, definire esplicitamente il repository remoto del ramo master:

$ git config branch.master.remote yourGitHubRepo.git

quindi a git pull origin master, seguito da a git statusdovrebbe restituire uno stato pulito (no avanti).
Perché? perché il master get fetch origin (incluso nel master git pull origin) non si aggiorna FETCH_HEAD(come spiega Charles Bailey nella sua risposta ), ma aggiorna anche il "ramo master remoto" all'interno del repository Git locale.
In tal caso, il master locale non sembrerebbe più "avanti" rispetto al master remoto.


Posso testarlo, con un git1.6.5:

Per prima cosa 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 repository GitHub creando un repo nudo (uno che può ricevere push da qualsiasi luogo)

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

Aggiungo una modifica al mio repository funzionante, che inserisco nel repository github (aggiunto come 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 home repo, clonato da GitHub, in cui apporto un paio di modifiche, push su 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

Poi clono 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 quel repo, git status menziona master geing prima di ' 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 questo è solo originnon è 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 repository che ha un'origine su github (o nessuna origine, solo un remoto 'github' definito), 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 avessi originpuntato solo su github, statussarebbe pulito per git1.6.5.
Potrebbe essere con un avviso "avanti" per git precedenti, ma comunque, un git config branch.master.remote yourGitHubRepo.gitdefinito esplicitamente dovrebbe essere in grado di occuparsene, anche con le prime versioni di Git.


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 di GitHub e il mio ramo principale locale sta monitorando origin / master. Per quanto riguarda il mybranch, sono abbastanza sicuro di averlo creato dal ramo origin / mybranch, che dovrebbe seguirlo automaticamente. Ma ancora, forse questo è il problema? Che il mybranch locale non tiene effettivamente traccia di origin / mybranch? PS: sto usando git 1.6.1 (tramite MacPorts).
Matthias,

C'è un comando git che mi fa vedere se un ramo locale sta monitorando un altro ramo? Non riesco a trovarlo nelle pagine di manuale.
Matthias,

Puoi vedere quali rami remoti vengono tracciati git remote show origin.
Ted Percival

2

Stai attento ad aggiungere tutto il tuo telecomando (tranne quello originfornito con il tuo clone originale) usando git remote add NAME URL? Ho visto questo bug quando sono stati appena aggiunti a git config.


L'ho fatto durante la clonazione del repository. Tuttavia, non l'ho fatto con ogni ramo. Ad esempio, mybranch vorrei prima recuperare da origin, quindi git checkout -b mybranch origin/mybranch. Secondo la pagina man di git-branch, origin / mybranch è il punto di partenza, e inoltre, afferma per --track: "... Usa questo se esegui sempre il pull dallo stesso ramo a monte nel nuovo ramo, e se non si desidera utilizzare "git pull <repository> <refspec>" in modo esplicito. Questo comportamento è l'impostazione predefinita quando il punto di inizio è un ramo remoto. "
Matthias
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.