Reputation: 14022
In Pro Git you can see:
Checking out a local branch from a remote-tracking branch automatically creates what is called a
tracking branch
(and the branch it tracks is called an upstream branch). Tracking branches are local branches that have a direct relationship to a remote branch. If you’re on a tracking branch and type git pull, Git automatically knows which server to fetch from and branch to merge into.
So Git knows it has directly merge from another branch into tracking branch
and it seems better to name these branches as downstream branches instead of upstream. But why they are named as upstream?
Upvotes: 0
Views: 495
Reputation: 488183
It's not entirely clear to me but I think this is the source of your confusion:
So Git knows it has directly merge from another branch into
tracking branch
...
This is wrong. That's not what a remote-tracking branch is and does.
First, let's make a note of how git references work. Regardless of the actual reference (branch name, tag name, refs/stash
for the git stash
command, or whatever), a reference, in git, is simply a name that resolves to a hash, such as 0f90a088a1161e812e7cf9ef9724f9bfcb4267ec
. Most (though not all) references have a full name that starts with refs/
. (Some references are indirect or symbolic, meaning they contain the name of another reference. The special HEAD
reference—this is one of the few that does not start with refs/
—is normally symbolic as it normally contains the name of the current branch. A symbolic reference must eventually resolve to a regular reference, which must in turn resolve to one of those SHA-1 hash values, with one special exception for what git calls an unborn branch, which I won't address here.)
Next, let's define the term "remote-tracking branch": A remote-tracking branch, in git, is simply any reference whose full name begins with refs/remotes/
. Similarly, a (regular, ordinary, not-remote-tracking) branch1 is any reference whose full name begins with refs/heads/
(and for completeness, a tag is any reference whose full name begin with refs/tags/
).
Typically your (single) remote is named origin
, since git clone url
creates a remote named origin
. This means your local git repository has origin/master
as one of its remote-tracking branches. The full name of origin/master
is actually refs/remotes/origin/master
, which—by definition—makes it a remote-tracking branch.
The initial git clone url
does one other thing that you normally never need to adjust, but is useful to know because it is how remote-tracking branches are actually implemented. The git clone
sets up the fetch refspecs for origin
, which you can see with:
git config --get-all remote.origin.fetch
The output from this command will read:
+refs/heads/*:refs/remotes/origin/*
Note that on the left hand side of the colon (:
) character, we see refs/heads/*
. These name (regular, ordinary, local) branches; the *
part matches everything, so this means every branch as seen on the remote. On the right, we see refs/remotes/origin/*
. These name remote-tracking branches—specifically, our own remote-tracking branches for the remote named origin
. The *
in this case is replaced with whatever our git matches when it's connected to origin
during a git fetch
.2 (For completeness, the +
at the front sets the force flag, so that git fetch
will always update the remote-tracking branch.)
What this means is that whenever you fetch from the remote, your git makes your remote-tracking branches match their git's branches. It does so not by doing any merging, but simply by copying whatever they have and then creating or replacing the remote-tracking branch so that it exactly matches what they have at the time the git fetch
runs.
This means that a remote-tracking branch is your git telling you "this is what I saw on the remote, the last time I checked."
This is also why we can call the remote an "upstream". Suppose, for instance, that remote origin
refers to the official github repository for some project. You clone the project to a local repository (not even another github fork, just a regular git repository on your local machine) and maybe make a few changes. Then, after some time, you may decide to find out what's happened in the official repository since you cloned. You need only run git fetch origin
to pick up their changes. If they have changed their master
branch, you will immediately and automatically see these changes in your origin/master
remote-tracking branch.
Since your work is derived from their work, your code is "downstream" of theirs, and theirs is "upstream" of yours. Once you have fetched their new work, it's up to you how, or even whether, to modify your earlier changes to use their new version. You can merge their new work, rebase onto their new work, ignore their work, or do whatever you like—but as long as your work is based on theirs, they are "upstream" of you and you are "downstream" of them.
If your local branch—whatever its name is, master
or some other name—has one of your remote-tracking branches set as its "upstream" (with git branch --set-upstream-to
or similar), your git status
commands will, after you git fetch
, tell you about commits you have that they don't ("ahead 3") and commits they have that you don't ("behind 9"). You can then use git merge
or git rebase
to merge or rebase your changes with theirs, but this is not automatic, it's done only when you tell your git to do it.3
1The term branch in git is actually ambiguous: it can mean either a branch name, which is that thing starting with refs/heads/
, or it can refer to a portion of the commit graph. See this question for details.
2For some time, since git 1.8 or so, git also opportunistically updates remote-tracking branches on git push
operations. Specifically, if you run git push remote ref
and the push successfully updates ref
on remote
, the push code also updates your remote-tracking branch for remote
's ref
. For example, after a successful git push origin master
, your git knows where origin/master
should point, so your git updates your copy of origin/master
.
3If you run git pull
instead of git fetch
, know that git pull
starts by doing git fetch
, then running either git merge
or git rebase
. This is meant as a convenience short-cut, since it's pretty common to want to merge or rebase and then remember at the last moment that you also need to git fetch
first. For beginners, though, I think it's much better to keep the two steps separate.
Upvotes: 2