This stuff is very confusing. Git could be more consistent here, if enough of its commands had been written at the same time. They weren't—these various operations were put together over the course of several years—and backwards compatibility limited the Git authors.
Let's define some terms:
A remote is a short name, like origin
. The purpose of this short name is several-fold:
It stores a URL, so that you don't have to keep typing it. The URL might be https://github.com/user/project.git
or ssh://git@github.com/user/project.git
or something much longer, but the first remote name is almost always origin
and that's only six letters, hence much easier to type.
It acts as a prefix for remote-tracking names.
A remote always represents some other Git. That other Git is a full Git repository (although often it's a --bare
repository, meaning it has no working tree).
A branch name is a name like master
or topic
or feature/short
or whatever. There are some constraints on branch names—for instance, they may not contain two or more adjacent dots, so that hello.world
is OK but well...yes
is not.
A remote-tracking name is a name like origin/master
or origin/topic
. It's built out of two parts: a remote name, like origin
, and a branch name as seen on that other Git.
When your Git calls up another Git, via a remote name like origin
, your Git has that Git list out all of its branch names. These branch names correspond to specific commits in that other Git repository. Your Git will get these commits from that Git, if you don't already have them. Then, your Git will remember their branch names by creating or updating your remote-tracking names. So if their master
represents commit a123456
, your origin/master
will now be updated to hold a123456
too.
In general, Git can turn either a branch name like master
, or a remote-tracking name like origin/master
, into a commit hash ID. Running:
git rev-parse master
will show you what hash ID your Git has for your master
right now, for instance.
When you run git merge
—which is an early command, predating even the existence of remote names like origin
—what you need to give to it is name(s) of one or more commits. So git merge origin/master
suffices here, because origin/master
names one specific commit. git merge topic
also suffices, if you have a branch named topic
, because your branch name topic
names one specific commit.
If you give git merge
the names of two or more commits, Git will (well, sometimes will) perform what Git calls an octopus merge. For instance:
git merge topic1 topic2 topic3
performs a merge that combines three topic branches with whatever your current branch is (perhaps master
).
If you've been running:
git checkout master
git merge origin master
you have been asking Git to do one of these octopus merges. The commit you're asking to merge is origin
.
Now, origin
itself is not a remote-tracking name. But try running:
git rev-parse origin
as well as:
git rev-parse origin/master
You will almost certainly see that both commands produce the same commit hash ID. The reason is that the name origin
by itself, when used where Git expects a branch or remote-tracking name, is expanded to read origin/HEAD
. Then, origin/HEAD
is expanded too, usually to origin/master
. So this winds up meaning git merge origin/master master
.
Meanwhile, you are already on your own master
so git merge master
would not do anything anyway. So this particular "octopus" merge collapses into a regular merge of your master
with your origin/master
, which is your Git's memory of some other Git's master
.
In general you should use git merge origin/master
here, to be explicit and not depend on origin/HEAD
mapping to origin/master
. Moreover, you may want to make use of another Git feature, called the upstream setting of a branch name, so that you can just run git merge
(without any extra names at all). But it's been working because origin
here got expanded to origin/HEAD
which meant origin/master
, and your octopus merge request got turned into a more ordinary merge in the end.
Note that the git pull
command is quite different: it's meant as a convenience. It runs git fetch
first, then it runs a second Git command. The default second Git command is git merge
. When it does the git fetch
step, it needs a remote—a name like origin
. So the origin
in git pull origin master
is for git fetch
. Then, when it does the second step, it needs to know the name of the branch you wanted as seen on the other Git. So the master
in git pull origin master
means master
as seen over on origin
, which your Git remembers as origin/master
for non-pull
commands like git merge
.
That's where all this confusion comes from: git pull
predates remotes, and you used to do things like git pull url master
. Here it was clear that the url
part was to get to some other Git, and then master
meant their master
. Remotes—like origin
—didn't exist, and therefore remote-tracking names like origin/master
didn't exist either. Now they do, and we have the situation we have.