I am currently on the master branch of my repo. How do I switch to the remotes/OriginalRepo/master
branch? git checkout remotes/OriginalRepo/master
does not work

- 3,872
- 6
- 22
- 37

- 284
- 2
- 12
-
Does this answer your question? [What is a tracking branch?](https://stackoverflow.com/questions/4693588/what-is-a-tracking-branch) – Nov 25 '20 at 16:14
2 Answers
Assuming that you did a pull
and you're up to date , you can do: git checkout --track remotes/OriginalRepo/master

- 3,872
- 6
- 22
- 37
TL;DR
You will need to make your own branch name. Because you already have one branch named master
, you'll have a problem. There's no single correct solution, but consider deleting your existing master
, if you don't need it. Then you can use dejdej's answer.
If you want to keep your existing master
, come up with another name for this branch. Let's say you choose xyzzy
for some reason:
git checkout -b xyzzy OriginalRepo/master
will do the trick here. You may eventually run into some more issues, but we'll leave them for another answer.
Long
Git documentation uses terms that I find confusing (both to me and to others when I am showing them how to use Git). So instead of Git's terminology, I use my own:
A branch name is a name that you have available for you to use. In your output image,1
Relayout
,getStarted
,master
, andsignup
are branch names. These are all in green (well, there's one weirdness mentioned in the next bullet point).A remote-tracking name is a name that your Git has created, in your repository, based on a branch name that your Git saw int some other Git repository. In your image,
remotes/OriginalRepo/Relayout
,remotes/OriginalRepo/getStarted
, and so on are remote-tracking names. These are all in red, except for the weirdness right afterremotes/origin/HEAD
.
So we have two kinds of names here: branch names and remote-tracking names.2 The remote-tracking names are your Git's way of remembering some other Git's branch names, but they're not branch names themselves.
Note how in your git branch -a
output all the remote-tracking names start with remotes/
. If you run git branch -r
, you'll get the same set of remote-tracking names, but this time Git will leave off the word remotes/
. You'll have OriginalRepo/Relayout
and so on. These are still the same names! Git has merely left out some stuff that we didn't need this time.
All of Git's names—branch names, tag names, remote-tracking names, and other special purpose names like the one for git stash
and the ones for git bisect
and so on—work the same way and use a general mechanism. Git's term for this is refs or references. They start with refs/
and then normally have another word, like remotes/
, that defines which group of names they go into, i.e., which kind of name they are. Branch names all start with refs/heads/
, tag names all start with refs/tags/
, and remote-tracking names all start with refs/remotes/
. Whenever it's clear enough—which is almost always—you can leave off the refs/
part, and whenever it's clear enough, you can also leave off the heads/
or tags/
or remotes/
part.
So that's why origin/master
is sufficient: as long as you didn't make your own branch name origin/master
,3 origin/master
will be short for your refs/remotes/origin/master
remote-tracking name. But if you like, you can write remotes/origin/master
or refs/remotes/origin/master
. It sometimes feels a bit like Stella calling out Harcourt Fenton Mudd.
1StackOverflow guidelines generally ask that you post cut-and-pasted text rather than images, but in this particular case, the image has the advantage of retaining the colors.
2Git calls them remote-tracking branch names, but I find that the word branch in the middle of this phrase just makes everything messier and more confusing. They're not actually branch names—well, not in your Git repository, anyway.
3Don't do it. Git won't get confused as to which one is which, but you will. But if you did it just because I said not to, you can use heads/origin/master
or refs/heads/origin/master
to refer to the branch name, and remotes/origin/master
or refs/remotes/origin/master
to refer to the remote-tracking name. Well, mostly. Some commands don't like the extra verbiage!
Checkout, branches, and detached HEADs
With the terminology out of the way, let's look at the question itself again:
How do I switch to the
remotes/OriginalRepo/master
branch?
You don't. It's not a branch. It's a remote-tracking name.
git checkout remotes/OriginalRepo/master
does not work
But git checkout remotes/OriginalRepo/master
does work, for some definition of "work". It's just that it gets you what Git calls a detached HEAD.
What's going on here seems complicated at first, but it's not, really. The trick is that Git does not care about branches. Git cares about commits. Branches—or more precisely, branch names—exist to help us, and Git, find the commits. What matters is not the branch names, though, but rather the commits themselves.
The git checkout
command actually has multiple functions. In fact, it has too many functions: in Git 2.23 and later, it's been split into what is roughly two halves. One is git switch
and the other is git restore
. The existing git checkout
command remains, and still does both sets of jobs. We won't look at one entire set at all, and will concentrate here only on the other set: the half of the jobs that are now done with git switch
.
These jobs involve extracting a commit, and also setting up your HEAD. To get any work done in Git, we have to extract a commit. Let's look at why this is the case.
Commits
A Git commit is a real, tangible thing. To access a commit in Git, we must tell Git its true name. But the true name of a commit is a big ugly random-looking hash ID, like faefdd61ec7c7f6f3c8c9907891465ac9a2a1475
for instance. There's no way for a human to remember these things. Fortunately we don't have to; but we'll get to that in a moment. First, let's look at what's inside one of these things.
A Git commit consists of two parts:
There is a snapshot of all the files that Git knew about, at the time you, or whoever, made the commit. This snapshot is completely, totally read-only, and the files stored inside it are in a special, read-only, Git-only, compressed and de-duplicated format, that only Git itself can use.
Besides the snapshot—the main data—each commit contains some metadata, or information about the commit itself. The metadata include the name and email address of the person who made the commit, the date-and-time of the commit, and so on.
One crucial piece of information that Git sticks into the metadata for each commit is the raw hash ID of some previous commit, or in some cases, more than one previous commit. This is how Git stores history. The latest commit has inside it the hash ID of the next-to-latest commit. That commit has inside it the hash ID of an earlier commit. This repeats, so that in a simple case of a nice linear chain of commits, we have something we can draw like this:
... <-F <-G <-H
where H
stands in for the actual hash ID of the latest commit. By giving Git the raw hash ID H
, Git can see what's in that commit: all the source (in the frozen, Git-only format), and also the metadata, including the hash ID of earlier commit G
.
This earlier commit hash ID allows Git to find G
, and extract it—all of it, or just the metadata, or whatever—which in turns allows Git to find F
, and so on. So this means that in order to use the entire chain of commits, all we really need is some way to remember hash ID H
.
To use the files from the commit, though, we'll need to have Git extract them. Git will copy those files out of the commit, restoring them to normal everyday files, which we can actually use to do work. The process of extracting some commit is the main work of git checkout
(or in 2.23-and-later, git switch
).
The files you'll work with, extracted from some commit, are in what Git calls your working tree or work-tree. There's always—well, almost always—one initial work-tree for a repository; you can add more, with git worktree
, later, if you like.
Branch names
Now that we know how commits work and what they do for us—store files and act as history, with these backwards-pointing chains of commits—now we can finally understand how Git uses a branch name. A branch name like master
or signup
simply holds the hash ID of one commit. By definition, that commit is the last commit that is "on that branch". Let's draw this—it probably isn't right, but it's meant to give the flavor of how these work:
I--J <-- signup
/
...--G--H <-- master
\
K--L <-- Relayout
Here, we show six commits—there are probably lots more before commit G
—where each commit points backwards to one previous commit: commit J
, which is the latest on signup
, points backwards to commit I
. Commit I
points backwards to commit H
. (The connecting lines really should have arrow-heads pointing backwards, but I can't draw those very well on StackOverflow.) Commit L
points back to K
, which also points back to H
. Commit H
points back to G
, which points back to whatever else might exist.
An interesting feature of Git is that the commits that are on master
are also on both of the other two branches. Git says that a commit is "on" some branch if, by starting with the branch name and the commit it selects, we can work backwards to find some other commit.
We can also have more than one branch name point to one particular commit. For instance, in this or some other repository, we could have:
...--P--Q <-- br1, br2, br3
Here, all three branch names select the same commit, commit Q
. The commits leading up to and including Q
are on all three branches.
Whenever we have more than one branch name, though, we need one more piece of information. In particular, how do we know which branch name we are using? Git's answer to this is the special name HEAD
, which must be written in all capitals like this.4 We "attach" the name HEAD
to exactly one branch name:
I--J <-- signup
/
...--G--H <-- master (HEAD)
\
K--L <-- Relayout
When HEAD
is attached to master
like this, git branch
shows an asterisk next to the name master
, to note that we're currently using the name master
to find the commit whose hash ID is H
.
Whenever we make a new commit, Git makes the commit itself—the snapshot with its metadata—so that the new commit points back to the current commit, as found using the name HEAD
. The new commit gets a new, unique, big ugly hash ID. Git immediately stores the new hash ID in the current branch name. So if we have the above, and make new commit N
, we get:
I--J <-- signup
/
...--G--H--N <-- master (HEAD)
\
K--L <-- Relayout
Note how no existing commit has changed. No commit can ever change: that's how Git makes sure we can always get back anything we committed. All we did was add the new commit, N
, that points back to existing commit H
, and make the name master
point to new commit N
. The name master
is the one that got updated—and N
's parent is H
—because HEAD
is attached to master
.
4On a typical macOS system, you can sometimes get away with writing head
, in lowercase, instead of HEAD
in all-capitals. This breaks once you start adding more work-trees, so don't get into the habit. If you don't like typing HEAD
because of all the uppercase, consider using its one-character synonym @
.
Detached HEAD
If you run:
git checkout OriginalRepo/master
you get, as we noted earlier, a "detached HEAD". That's because, just like branch names, remote-tracking names point to one commit—but unlike branch names, Git won't let you attach the special name HEAD
to a remote-tracking name, and OriginalRepo/master
is one of those.
So, suppose we have, say, this:
...--G <-- OriginalRepo/master
\
H <-- master (HEAD)
If we run git checkout
on the name OriginalRepo/master
, we're asking Git to extract commit G
. That's the commit whose hash ID is stored in the name OriginalRepo/master
. But Git can't attach HEAD
to that, because that's not a branch name, it's a remote-tracking name instead. So we get:
...--G <-- OriginalRepo/master, HEAD
\
H <-- master
In this detached-HEAD mode, we have the commit extracted. We can even make a new commit N
just like before, but if we do, the special name HEAD
gets updated directly:
N <-- HEAD
/
...--G <-- OriginalRepo/master
\
H <-- master
If we use git checkout master
, say, to re-attach HEAD
to a branch name, we end up with this:
N ???
/
...--G <-- OriginalRepo/master
\
H <-- master (HEAD)
Commit N
still exists. It's still there in your repository! But there is no name for it. The only name that will work is the raw hash ID. Did you write it down somewhere?
The solution to this dilemma is to add a branch name
If we're on commit N
, having made it, we can just add a new branch name right then and there:
N <-- xyzzy, HEAD
/
...--G <-- OriginalRepo/master
\
H <-- master
We can do this with, e.g., git branch xyzzy
. That creates a new branch name xyzzy
pointing to the current commit (by writing the current / HEAD
-commit hash ID into the new name). We can then attach HEAD
to xyzzy
if we like, with git checkout xyzzy
. We don't change commits—we were already on commit N
—but now we have:
N <-- xyzzy (HEAD)
/
...--G <-- OriginalRepo/master
\
H <-- master
and any new commits we make will update the name xyzzy
.
Or, if we don't yet have commit N
and just have this:
...--G <-- OriginalRepo/master
\
H <-- master (HEAD)
We can tell Git to extract commit G
and make it current, then add a new branch name xyzzy
and get on it. We could do this with:
git checkout OriginalRepo/master
git branch xyzzy
git checkout xyzzy
or we can shorten this to:
git checkout -b --no-track xyzzy OriginalRepo/master
You might say: wait, what is this --no-track
thing? It's not really clear whether you should use it, but probably you shouldn't use it. I put it in because this makes the git checkout -b
act exactly the same as the three command variant, git checkout
(for detached HEAD) followed by git branch
followed by git checkout
(to attach HEAD). This gets us into our last little wrinkle.
Branches have upstreams
In Git, each branch name can have one upstream set. The upstream setting of a branch is not crucial. In fact, you can have branches that don't have any upstream. The purpose of setting an upstream is to make some things convenient.
There's another name for the upstream setting stuff. It is a terrible name, but it shows up in Git because of the --track
and --no-track
options. The bad name for this is to call a branch with an upstream set, a tracking branch.
There are a lot of reasons that this is a terrible name. The most important one, I think, is that Git has the notion of tracked files vs untracked files, and this is completely separate from branch upstream settings. There are also those remote-tracking names (or "remote-tracking branch names" if you prefer the Git terminology), and they're also different from upstreams. So let's use the new term, upstream, to talk about the upstream of a branch.
Typically, the upstream of a branch name like master
is a remote-tracking name like origin/master
.5 This makes the git status
command more useful, and makes it possible to run git pull
, git merge
, and git rebase
without typing in as much stuff. That's its main function, really. Setting the upstream makes it easier to run other Git commands, and/or makes their output more useful.
But if the upstream of master
is normally origin/master
, for instance, what would be the pair of names for OriginalRepo/master
? Obviously, you should have another branch named master
whose upstream is OriginalRepo/master
. But there are two problems:
- A branch name can only hold one hash ID.
- A branch name can only have one upstream.
Since the name master
is the same as the name master
, you'll have to break the symmetry here somehow. You can use a silly name like xyzzy
for one of these, for instance: xyzzy
can store the same hash ID as OriginalRepo/master
, and can have OriginalRepo/master
as its upstream. That solves all of those problems.6
The way to set, or unset, an upstream on an existing branch is to use git branch
:
git branch --set-upstream-to=OriginalRepo/master xyzzy
sets the upstream of xyzzy
to OriginalRepo/master
. Meanwhile:
git branch --unset-upstream xyzzy
strips out the upstream entirely (if you ever want to do that; there's sometimes reasons, but it's never required).
When you create a new branch name with git checkout -b
or git branch
, however, you get to choose whether the new name has an upstream already set. The flag for this is --track
or --no-track
. Using --no-track
means don't set up an upstream and using --track
means do set up an upstream.
So, if you do want to have xyzzy
have OriginalRepo/master
as its upstream:
git checkout -b xyzzy --track OriginalRepo/master
does that explicitly. The --track
and --no-track
are actually defaults, in a complicated way. I'm going to leave out the full details as this answer is already too long.
5The reason these are called remote-tracking names in the first place is that Git has an entity called a remote. A remote is mainly a short name, like origin
or upstream
or OriginalRepo
, under which you can store a longer URL. But Git then uses the remote name to construct the remote-tracking names, which track (i.e., remember the hash IDs from) the branch names in the Git that your Git reaches at that remote. You can pretty easily get dizzy from all this stuff: a remote holds a URL; a remote-tracking name is built from a remote name plus a branch name; a branch name can have an upstream set, and is then sometimes said to be a "tracking branch"; and files are tracked or untracked, which has nothing to do with any of that!
6This does introduce one problem of its own, which is that one part of Git really wants the names to be symmetric. In particular, if you ever want to use git push
to send updates directly to OriginalRepo
, and you have push.default
set to simple
, Git will demand that the upstream of xyzzy
be OriginalRepo/xyzzy
, not OriginalRepo/master
. But if you never need to push there, that's not going to be a stumbling block, and if you ever do need that, there are multiple ways around this problem.

- 448,244
- 59
- 642
- 775