91 votes

'git pull origin mybranch' laisse mybranch local avec N commits d'avance sur origin. Pourquoi ?

J'ai juste observé quelque chose de bizarre à propos git pull ce que je ne comprends pas.

Vendredi, j'ai travaillé sur une branche locale. appelons-la mybranch . Avant de quitter le bureau, je l'ai poussé sur origin (qui est mon repo github) : git push origin mybranch .

Hier, à la maison, j'ai pull J'ai transféré ma branche sur mon ordinateur portable, j'ai continué à coder, puis j'ai poussé mes modifications sur github (origin).

Maintenant, je suis de nouveau au travail et j'ai essayé de transférer les modifications d'hier sur ma machine de travail (je n'ai rien changé au repo local de mon lieu de travail pendant le week-end) :

git pull origin mybranch

qui a provoqué une fusion en avance rapide, ce qui est bien. J'ai ensuite fait une git status et il a dit :

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

Hein ? Comment peut-il avoir 6 commits d'avance alors que je n'y ai même pas touché pendant le week-end, et que je viens de le retirer de l'origine ? Donc j'ai lancé un git diff origin/mybranch et les différences étaient exactement les 6 changements que je viens de retirer à distance.

Je n'ai pu "réparer" cela qu'en exécutant git fetch origin :

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

Apparemment, il manquait des objets de référence dans mon dépôt local, mais comment est-ce possible ? Je veux dire, un pull fait déjà un fetch, et je n'ai pas travaillé sur autre chose que cette branche, donc un git fetch origin y git fetch origin mybranch devrait avoir le même résultat ?

Dois-je toujours utiliser git pull origin au lieu de git pull origin branchname ?

Je suis confus.

113voto

Charles Bailey Points 244082

git pull appelle git fetch avec les paramètres appropriés avant de fusionner les têtes explicitement récupérées (ou si aucune la branche distante configurée pour la fusion) dans la branche courante.

La syntaxe : git fetch <repository> <ref> donde <ref> est juste un nom de branche sans deux-points est une récupération 'one shot' qui ne fait pas une récupération standard de toutes les branches suivies du distant spécifié mais récupère juste la branche nommée dans le fichier FETCH_HEAD .

Mise à jour : pour les versions de Git depuis 1.8.4, s'il existe une branche de suivi distante qui suit la référence que vous avez demandé de récupérer, alors la branche de suivi sera maintenant mise à jour par fetch . Ce changement a été fait spécifiquement pour éviter la confusion que le comportement précédent a causé.

Lorsque vous effectuez git pull <repository> <ref> , FETCH_HEAD est mise à jour comme ci-dessus, puis fusionnée dans votre version vérifiée de l'article HEAD mais aucune des branches de suivi standard du dépôt distant ne sera mise à jour (Git <1.8.4). Cela signifie que localement, il regarde comme si vous étiez en avance sur la branche distante, alors qu'en fait vous êtes à jour avec elle.

Personnellement, je fais toujours git fetch suivi par git merge <remote>/<branch> parce que je peux voir les avertissements concernant les mises à jour forcées avant de fusionner, et je peux prévisualiser ce que je fusionne. Si j'utilisais git pull un peu plus que moi, je ferais une simple git pull sans paramètres la plupart du temps, en s'appuyant sur les éléments suivants branch.<branch>.remote y branch.<branch>.merge pour "faire ce qu'il faut".

3voto

VonC Points 414372

Qu'est-ce que git remote -v show les retours en matière d'origine ?

Si l'origine pointe vers github, le statut doit être à jour, et non en avance sur un dépôt distant. Du moins, avec le Git1.6.5 que j'utilise pour un test rapide.

Quoi qu'il en soit, pour éviter cela, définissez explicitement le repo distant de la branche master :

$ git config branch.master.remote yourGitHubRepo.git

alors un git pull origin master suivi d'un git status devrait renvoyer un statut propre (pas d'avance).
Pourquoi ? parce que le get fetch origin master (inclus dans le git pull origin master) ne mettrait pas seulement à jour FETCH_HEAD (comme Charles Bailey explique dans sa réponse ), mais il faudrait également mettre à jour la "branche maîtresse distante" dans votre dépôt Git local.
Dans ce cas, votre maître local ne semblerait plus être "en avance" sur le maître distant.


Je peux tester cela, avec une git1.6.5 :

D'abord je crée 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"

Je simule un repo GitHub en créant un repo nu (qui peut recevoir un push de n'importe où).

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

J'ajoute une modification à mon repo de travail, que je pousse vers le repo github (ajouté en tant que remote).

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

Je crée un repo maison, cloné de GitHub, dans lequel je fais quelques modifications, poussées vers 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

Je clone ensuite workrepo pour une première expérience

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

Dans ce repo, le statut git mentionne que master est en avance sur '. 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)

Mais c'est seulement origin n'est pas 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)

Mais si je répète la séquence dans un repo qui a une origine vers github (ou pas d'origine du tout, juste un 'github' distant défini), le statut est propre :

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 j'avais seulement origin en pointant sur github , status serait propre pour git1.6.5.
Il se peut que ce soit avec un avertissement "en avance" pour les git antérieurs, mais de toute façon, une git config branch.master.remote yourGitHubRepo.git défini explicitement devrait pouvoir s'en charger, même avec les premières versions de Git.

2voto

Pat Notz Points 46841

Avez-vous pris soin d'ajouter tous les éléments de votre télécommande (sauf origin qui est fourni avec votre clone original) en utilisant git remote add NAME URL ? J'ai vu ce bug lorsqu'ils viennent d'être ajoutés à la configuration git.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X