0

I thought git pull was like a git fetch + git merge. Being in branchA, I always do a git fetch and then a git merge origin/master. But today, being in a branchA, I tried git pull origin/master and it didn't work but doing a git pull origin master worked. Any thoughts?

Extra question, if an updated origin/master and the online version of master are the same, why bother to have origin/master, wouldn't it be more convenient to always work with the online version that is always updated, releasing us from the burden to alway be git fetching?

user33276346
  • 1,501
  • 1
  • 19
  • 38
  • Could you explain how "it didn't work" ? – Jona Apr 14 '20 at 15:19
  • Does this answer your question? [Differences between git pull origin master & git pull origin/master](https://stackoverflow.com/questions/2883840/differences-between-git-pull-origin-master-git-pull-origin-master) – phd Apr 14 '20 at 16:23
  • https://stackoverflow.com/search?q=%5Bgit%5D+difference+origin%2Fmaster+origin+master – phd Apr 14 '20 at 16:23

1 Answers1

2

I thought git pull was like a git fetch + git merge.

It is. However, the syntax one uses with git pull does not match the syntax one uses with pretty much every other Git command. This is due to history: git pull predates a number of improvements made in Git between pre-1.5 and post-1.6 Git versions. (Note that Git is now at version 2.26, so this is truly ancient history, dating back to 2005 or so. The oldest versions of Git that people still seem to use today are in the version 1.7 range—but when you run git pull, you're harking back to the pre-stone-age, dinosaur Git 1.5 era.)

[but] I tried git pull origin/master and it didn't work [while] git pull origin master worked

That is because this is the special syntax just for git pull.

Read the git pull documentation carefully for exceptions (of which there are plenty), but in general, most of the arguments you pass to git pull, git pull passes to git fetch. Just as you would not run:

git fetch origin/master      # wrong

you cannot run

git pull origin/master       # also wrong: this runs git fetch origin/master

You can, however, run:

git fetch origin master

Here origin is a remote and master is a refspec (see the git fetch documentation for more about remotes and refspecs). This specifically limits your git fetch operation to fetch only commits new-to-you that are on their master, so as to update only your origin/master.1

After the fetch is complete, pull runs merge, or if you so specify, rebase, on some set of branch-head commits.2 The general idea here—which goes back to that pre-Git-1.6 history I mentioned—is that, having fetched some commit(s) from some other Git, you now wish to incorporate those commits into your current branch.

There was a time, in early Git, when the entire concept of remote did not exist, and hence there were no remote-tracking names: there was no origin at all, hence no origin/master. It was therefore important to incorporate their commits immediately, lest your Git run a garbage collection pass and remove the new commits you obtained.

In the post-1.6 era—i.e., since 2006 or so—it's been safe to collect the commits and let them sit there for a while, while you look them over, think about them, or even ignore them entirely for a while. The remote name origin introduced the remote-tracking names, such as origin/master, which retains those commits indefinitely. There is no longer any need for a mad rush of shoving those commits into one of your own branches, in order to prevent them from being removed.

The bottom line is: If you find git pull convenient, use it. If not, don't. Remember that the arguments you'll use, if you use arguments, are unique to it. It's just a combination of git fetch, plus an immediate second command to incorporate some fetched commits into the current branch. I find this in-convenient, most of the time: I like to inspect the fetched commits first. If you don't use git pull, you'll name the incoming commits with remote-tracking names like origin/master, but if you do use git pull, you can't use these names in the git pull command itself, because it is being compatible with ancient times when these names did not exist.


1This kind of git fetch will update your origin/master in any modern Git, but in Git versions before 1.8.4, it will leave origin/master un-updated.

2The commits chosen as arguments to merge or rebase are those from references that you specifically named on the command line, if you named any. Otherwise, the (single) commit chosen as an argument is the one corresponding to the upstream setting of the current branch.

In some corner cases, git pull runs something other than merge or rebase as its second command. The most interesting of these special cases is pulling into a completely empty repository: here, neither git merge nor git rebase will do anything, so git pull essentially just runs git checkout instead. This one special case obviously happens only once in any given repository.

torek
  • 448,244
  • 59
  • 642
  • 775
  • If I do a `git pull`, it will `git fetch` (update my origin/x's) and `git merge` origin/master to my branch only. On the other hand, if I do `git pull origin master`, it will `git fetch` (update only my origin/master) and `git merge` origin/master to my branch only. Are these assumptions correct? – user33276346 Apr 15 '20 at 20:54
  • @user33276346: With no additional arguments—i.e., run as `git pull`—your Git will look up the *upstream setting* for your current branch. What branch are you on? What is its upstream? Break that up into its parts—e.g., `origin/master` becomes `origin master`—and the first part gives you the remote for the `git fetch`. Put them back together and they give you the remote-tracking name for the subsequent `git merge`. The fetch that `git pull` runs will be an "unlimited" fetch, updating `origin/*`. – torek Apr 16 '20 at 00:17
  • But, with additional arguments—e.g., `git pull origin master`—your Git will run `git fetch origin master`, which is a limited fetch that just updates your `origin/master`. Then your Git will run the equivalent of `git merge origin/master`. – torek Apr 16 '20 at 00:19
  • So if, say, you're on your own `feature/two` whose upstream is `origin/feature/two`, `git pull` would update `origin/*` and merge with the updated `origin/feature/two`, but `git pull origin master` would update `origin/master` and merge with the updated `origin/master`. – torek Apr 16 '20 at 00:19
  • (See above for all the caveats about old Git versions predating 1.8.4 and the like.) – torek Apr 16 '20 at 00:20
  • Awesome. So to summarize: `git pull` = `git fetch` + `git merge origin/branch`. Additionally, git pull and `git pull origin branch` only differ in that the latter will only "update" origin/branch and not all origin/* as `git pull` does. If so, THANK YOU #torek. I hope this helps others as it helped me. – user33276346 Apr 16 '20 at 04:18
  • Yes - though the summary misses tons of tricky little traps, such as things like ancient versions of Git behaving differently. Git 1.7.x and 1.8.x (for various x values) are still "out there" in some distributions, so these traps are sometimes important. – torek Apr 16 '20 at 06:39