Posted By: Anonymous
If I have cloned a git repository, I only have the master branch on my local machine. If the actual repo has a branch I’d like to work on, say alpha, how exactly do I work on that branch locally then push to create a PR for that branch?
I’ve heard that maybe I need to do:
git switch alpha (which creates the same branch on the repo on my local machine). Or do I need to do git switch origin/alpha
Then when I’m in that branch and make changes, how do I push to that branch then make a PR on github?
If I have cloned a git repository, I only have the master branch on my local machine.
Branchesâ€”or more precisely, branch namesâ€”exist to find commits. They are not the only way to find commits, though.
When you first clone (i.e., copy-via-Git) some existing Git repository, you get all of the other Git repository’s commits,1 but none of their branches. That state exists for a few nanoseconds or milliseconds or so, and then
git clone creates one branch name in your copy.2 Typically that’s
main, depending on the other Git (see footnote 2). Since you mentioned
master, let’s go with that one.
So: if the other repository, the one you’ve copied, had, say, six branch names … what happened to the other five? Well, the answer is: the same thing that happened to their
master. Your Git renamed all their branches. Your Git changed them all into remote-tracking names by sticking
origin/ in front of each name.3 So their six branches became six remote-tracking names in your Git repository.
Your Git then created a new
master in your own repository, just so that you could have a branch to be on. Your own
master now selects the same commit as their
master, which is your
If the actual repo has a branch I’d like to work on, say alpha, how exactly do I work on that branch locally then push to create a PR for that branch?
Use any command to create the name. The "best" command is probably
git switch (since Git 2.23). Both
git switchâ€”the new, not quite so super-powered command that is safer to use than
git checkout4â€”and the old
git checkout have what Git calls DWIM mode, where if you ask to get on a branch that does not (yet) exist, Git will look to see if there’s some remote-tracking name that’s otherwise identical. So if there is an
origin/alpha and you run
git switch alpha, your Git will create your own
alpha, pointing to the same commit as your
origin/alpha, which is of course the same commit that their Git hasâ€”or had at the time of cloningâ€”as the last commit in their
Generally, you’ll want your
alpha to identify this same last commit as theirs. If your Git repository could be out of dateâ€”if you think they may have added new commits since your
git cloneâ€”you should probably run
git fetch first. The
fetch command has your Git call up their Git, list out their branch names, and then get any new commits they have, that you don’t yet, and then update your remote-tracking names.
When you ran
git clone, your
git clone essentially used
git fetch to get all their commits, initially. The code is built into
git clone, so it doesn’t literally run
git fetch, but it’s the same code: your Git created an empty (no-commits) repository, then ran
git fetch against their Git. All their commits were new-to-you so your Git got all their commits. Then your Git created or updated any remote-tracking names based on their branch names. All their branch names were new-to-you, so your Git created all the remote-tracking names.
git fetch calls up their Git, gets any new commitsâ€”you already have the existing onesâ€”and creates or updates your remote-tracking names again. That’s all it does, so it’s safe to run at any time. It does not check out any of their commits. It does not add their commits to your branches. It just gets new commits, if any, from them, and updates your remote-tracking names.
Anyway, once you have your own branch name, you can start adding your own commits. Every commit gets a unique hash ID, so your new commits will have a different hash ID from every commitâ€”even any new ones they make while you’re making new commits of your ownâ€”and your Git and their Git will be able to tell these apart, just by their hash IDs. (That’s why these hash IDs are so big and ugly: so that they can be unique.)
When your commits are ready for review or whatever other process you will use, you can send your commits to the other Git repository. You’ll have to have themâ€”the other Gitâ€”set one of their names to remember your new commits, though. Typically you’ll set a branch name in their Git repository. That might be a new name, or might be
alpha. You might then create a "pull request", which is a fancy GitHub thing (there’s a slightly different fancy Bitbucket thing, and a slightly different from both of those fancy GitLab thing, all called "pull requests"). All of these details depend on (a) what other Git repository you’re using and (b) the standard work-flow that everyone in your group uses, so it’s a little early to get into specifics here. The only thing we can say with some (but not complete) certainty is that you’ll probably send your commits using
git push, which is as close as Git gets to the opposite of
1It’s possible to get less than every commit, for various reasons and using various methods, but let’s just go with this as the initial view of cloning.
2If you don’t want
git clone to create one branch, use
git clone --no-checkout. If you want to control the name of the branch, use
git clone -b. Note that if you provide a tag name to
-b, the last step of
git checkout will not actually create a branch name either.
If you use neither
-b, your Git asks the other Git what branch name they recommend, and pretends you supplied that name as your
3The remote-tracking names actually live in a separate name space, under
refs/remotes/, and the
origin/ part assumes that you are using the standard first remote name. You can choose some other name with the
-o option to
git clone, though you probably should not, since all the introductory Git reading material you’ll find will assume
4It’s safer in the sense that, say, a hand sanding block is safer than a power sander: you won’t accidentally grind your knuckles right off with a hand sander. 🙂 More seriously, the old
git checkout command has a safe mode,
git checkout <em>branch</em>, and an unsafe "please wreck all my unsaved work" mode,
git checkout <em>file</em>. It’s really easy to accidentally invoke the
file version when you meant to invoke the safe
branch version. The
git switch command is different enough, and lacks the unsafe modeâ€”that’s in the new
git restore command insteadâ€”that it won’t destroy unsaved work like this. You can still destroy unsaved work, but you have to work harder to make that happen.
5The somewhat mis-named
git pull means run
git fetch, then run a second Git command. The default second Git command is
git merge. This is very different from
git push because
git push does not have a second step and never does any merging. That’s why
fetch is as close as we get to the opposite of
push: neither does any merging.