9

My understanding has always been that git pull is essentially a combination of git fetch and git merge ... but I have encountered it a number of times where pulling, then comparing shows changes that aren't mine until I also do a fetch:

(on branch blob):

git pull origin blob
git diff origin/blob  <- shows a bunch of changes that aren't from my but were just pulled from others
git fetch
git diff origin/blob  <- shows just my changes

Is my understanding of pull incorrect?

pinkboi
  • 259
  • 2
  • 9
  • This is assuming there are no remote changes between your `git pull` and explicit `git fetch` correct? – BlackVegetable Sep 20 '13 at 17:41
  • I wonder if `git fetch --all` would make a difference if used in your third step. I wouldn't think that your second fetch would make any difference at all; that's what is confusing me. – BlackVegetable Sep 20 '13 at 17:46

1 Answers1

17

This is a common source of confusion, so much so that the #git IRC channel has a canned help text for it, called !pull4:

We recommend against using 'git fetch/pull <remote> <refspec>' (i.e. with branch argument), because it doesn't update the <remote>/<branch> ref. The easy way to fetch things properly is to get everything: 'git fetch' or 'git pull' are sufficient if you have one remote; otherwise we recommend 'git fetch <remote>' (plus 'git merge <remote>/<branch>' if you wanted to pull/merge).

What's happening here is that git pull with no arguments does a git fetch on the "default remote" (typically origin), then git merges the remote branch corresponding to your current local branch. git pull <remote> does the same thing with an explicitly specified remote. However, the "four-word pull", git pull <remote> <branch>, fetches that branch into a temporary location, FETCH_HEAD, without updating your tracking branches, and then merges FETCH_HEAD into your current branch.

So, by using git pull origin blob, you are saying "I want to merge the latest version of the blob branch on the remote origin into my current branch, without updating any of my tracking branches or fetching any other data".

If your branch merge configurations are correct (and they probably are, since git clone and git checkout try to set them up automatically), you can just git pull or git pull origin and it'll fetch everything and then merge the branch corresponding to your currently-checked-out branch. If you want more explicit control, use git fetch and then git merge. git pull <remote> <branch> is rarely what you want.

(The reason the git fetch fixes things in your example is that, after the pull, your local branch has been updated with the latest remote commits, but the tracking branch hasn't been. git fetch updates the tracking branch with those commits, at which point the diffs start making sense again.)

ToxicFrog
  • 2,554
  • 18
  • 18
  • In what case do you really want the `git pull ` form? +1 – BlackVegetable Sep 20 '13 at 23:34
  • @BlackVegetable Honestly, I have no idea. I've never had a use for it. I guess it could be useful in workflows where you don't bother with tracking branches at all, for whatever reason? – ToxicFrog Sep 21 '13 at 00:04
  • Thanks. I did notice that git pull by itself doesn't have this issue. I sometimes want to do git pull origin whatever if I'm in a different branch but I kind of think just always doing fetch and merging from the origin/whatever branch. – pinkboi Sep 21 '13 at 01:20
  • The IRC help is a good idea but I thought you could manually go `git pull origin master:origin/master` and because of the colon-ed info on the right it would manually do a remote track branch? (but they show best common practice) – sabgenton Dec 13 '13 at 14:12
  • Could be some caveat with that I wouldn't know. – sabgenton Dec 13 '13 at 14:47
  • is there any documented rationale for *why* `git pull ` behaves differently? – lofidevops Oct 10 '16 at 08:33