91

I just observed something odd about git pull, which I don't understand.

On Friday, I worked on a local branch. let's call it mybranch. Before leaving the office I pushed it to origin (which is my github repo): git push origin mybranch.

Yesterday at home, I pulled mybranch to my laptop, did some more coding, and then pushed my changes back to github (origin).

Now I'm at work again, and tried to pull the changes from yesterday to my work machine (I didn't change anything in my work place's local repo over the weekend):

git pull origin mybranch

that caused a fast forward merge, which is fine. I then did a git status, and it said:

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

Huh? How can it be 6 commits ahead when I didn't even touch it over the weekend, AND just pulled from origin? So I ran a git diff origin/mybranch and the diffs were exactly the 6 changes I just pulled from remote.

I could only "fix" this by running git fetch origin:

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

Apparently, my local repo was missing some reference objects, but how can that be? I mean, a pull does a fetch already, and I didn't work on anything except that branch, so a git fetch origin and git fetch origin mybranch should have the same result?

Should I always use git pull origin instead of git pull origin branchname?

I'm confused.

4

3 回答 3

116

git pullgit fetch在将显式获取的头(或者如果没有为合并配置的远程分支)合并到当前分支之前使用适当的参数调用。

语法:git fetch <repository> <ref>where <ref>is just a branch name without Colon is a 'one shot' fetch 不会对指定远程的所有跟踪分支进行标准提取,而是仅将命名分支提取到FETCH_HEAD.

更新:对于自 1.8.4 以来的 Git 版本,如果有一个远程跟踪分支跟踪您要求获取的 ref,那么跟踪分支现在将更新为fetch. 进行此更改是为了避免以前的行为引起的混乱。

当您执行git pull <repository> <ref>时,FETCH_HEAD如上更新,然后合并到您的签出HEAD但不会更新远程存储库的标准跟踪分支(Git <1.8.4)。这意味着在本地看起来你领先于远程分支,而实际上你是最新的。

就我个人而言,我总是这样做git fetchgit merge <remote>/<branch>因为我会在合并之前看到任何有关强制更新的警告,并且我可以预览我正在合并的内容。如果我使用git pull的比我多一点,我会做一个git pull没有参数的普通当时,依靠branch.<branch>.remotebranch.<branch>.merge“做正确的事”。

于 2009-11-16T18:08:24.517 回答
3

git remote -v show原产地返回什么?

如果 origin 指向 github,则状态应该是最新的,而不是在任何远程 repo 之前。至少,我使用 Git1.6.5 进行快速测试。

无论如何,为避免这种情况,请明确定义 master 分支的远程 repo:

$ git config branch.master.remote yourGitHubRepo.git

然后 a git pull origin master,后跟 agit status应该返回一个干净的状态(没有提前)。
为什么?因为 get fetch origin master(包含在 git pull origin master 中)不仅会更新FETCH_HEAD(正如Charles Bailey在他的回答中解释的那样),而且还会更新本地 Git 存储库中的“远程主分支”。
在这种情况下,您的本地主机似乎不再“领先于”远程主机。


我可以用 git1.6.5 对此进行测试:

首先我创建一个工作仓库:

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"

我通过创建一个裸仓库(可以从任何地方接收推送)来模拟 GitHub 仓库

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

我在我的工作存储库中添加了一个修改,我将它推送到 github 存储库(作为远程添加)

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

我创建了一个从 GitHub 克隆的 home repo,我在其中做了一些修改,然后推送到了 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

然后我克隆 workrepo 进行第一次实验

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

在那个 repo 中, git status 确实提到了 master 领先于 ' 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)

但这只是origin不是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)

但是,如果我在一个起源于 github 的 repo 中重复该序列(或者根本没有起源,只是定义了一个远程 'github'),则状态是干净的:

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)

如果我只origin指向githubstatus对于 git1.6.5 来说是干净的。
对于早期的 git,它可能带有“提前”警告,但无论如何,git config branch.master.remote yourGitHubRepo.git明确定义的应该能够处理这个问题,即使是早期版本的 Git。

于 2009-11-16T12:48:53.407 回答
2

您是否小心使用添加所有遥控器(origin原始克隆随附的遥控器除外)git remote add NAME URL?当它们刚刚被添加到 git 配置中时,我已经看到了这个错误。

于 2009-11-16T14:14:15.460 回答