问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/61211167/git-fetch-git-merge-origin-master-vs-git-pull-origin-master