web-dev-qa-db-fra.com

'git pull Origin mybranch' laisse le local mybranch N s'engage devant Origin. Pourquoi?

Je viens d'observer quelque chose d'étrange à propos de git pull, que je ne comprends pas.

Vendredi, j'ai travaillé dans une succursale locale. appelons cela mybranch. Avant de quitter le bureau, je l'ai poussé vers Origin (qui est mon dépôt github): git Push Origin mybranch.

Hier à la maison, j'ai pulled mybranch sur mon ordinateur portable, fait un peu plus de codage, puis repoussé mes modifications vers github (Origin).

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

git pull Origin mybranch

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

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

Hein? Comment peut-il y avoir 6 engagements à l'avance alors que je ne l'ai même pas touché pendant le week-end, ET simplement tiré de l'origine? J'ai donc couru un git diff Origin/mybranch et les différences étaient exactement les 6 changements que je viens de tirer de la télécommande.

Je ne pouvais que "corriger" cela en exécutant git fetch Origin:

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

Apparemment, mon référentiel local manquait des objets de référence, 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 et 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.

91
Matthias

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

La syntaxe: git fetch <repository> <ref><ref> est juste un nom de branche sans deux-points est une extraction "à un coup" qui ne fait pas une extraction standard de toutes les branches suivies de la télécommande spécifiée mais récupère à la place juste la branche nommée dans FETCH_HEAD.

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

Lorsque vous effectuez git pull <repository> <ref>, FETCH_HEAD est mis à jour comme ci-dessus, puis fusionné dans votre extrait HEAD mais aucune des branches de suivi standard pour le référentiel distant ne sera mise à jour (Git <1.8.4). Cela signifie que localement, il semble que vous êtes 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> car j'obtiens des avertissements sur les mises à jour forcées avant de fusionner et je peux prévisualiser dans quoi je fusionne. Si j'ai utilisé git pull un peu plus que moi, je ferais un simple git pull sans paramètre la plupart du temps, en s'appuyant sur branch.<branch>.remote et branch.<branch>.merge pour 'faire la bonne chose'.

113
CB Bailey

Qu'est-ce que git remote -v show revient quand il s'agit d'origine?

Si Origin pointe vers github, le statut doit être à jour et non en avance sur un dépôt à distance. Au 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 référentiel distant de la branche maître:

$ git config branch.master.remote yourGitHubRepo.git

puis un git pull Origin master, suivi d'un git status devrait renvoyer un état propre (pas d'avance).
Pourquoi? car le maître d'origine get fetch (inclus dans le maître d'origine git pull) ne se contenterait pas de mettre à jour FETCH_HEAD (comme Charles Bailey explique dans sa réponse ), mais cela mettrait également à jour "branche maître distante" dans votre référentiel Git local.
Dans ce cas, votre maître local ne semble plus être "en avance" sur le maître distant.


Je peux tester cela, avec un git1.6.5:

Je crée d'abord 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 dépôt GitHub en créant un dépôt nu (celui qui peut recevoir Push de n'importe où)

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

J'ajoute un modif à mon dépôt de travail, que je pousse vers le dépôt github (ajouté en tant que télécommande)

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 dépôt maison, cloné de GitHub, dans lequel j'apporte quelques modifications, poussé 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 dépôt, git status mentionne master geing avant '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 ce n'est que 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 dépôt 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 pointant sur github, status serait propre pour git1.6.5.
Il peut s'agir d'un avertissement `` à l'avance '' pour git antérieur, mais de toute façon, un git config branch.master.remote yourGitHubRepo.git défini explicitement devrait pouvoir s'en occuper, même avec les premières versions de Git.

3
VonC

Êtes-vous prudent d'ajouter toute votre télécommande (sauf Origin qui est fourni avec votre clone d'origine) en utilisant git remote add NAME URL? J'ai vu ce bug quand ils viennent d'être ajoutés à la configuration git.

2
Pat Notz