git clone
defaults to copying only the (local) branches and tags of the other Git. You can get additional references, including remote-tracking names like remotes/savannah/oldstable
. But that's usually not a good idea. Instead, in your bare repository, make it have branches with these names.
This is all a little bit tricky at first, but eventually it all starts to make sense. These names arise from the use of two separate Git repositories. Each Git repository has its own branch names, so:
A branch name is a reference whose full name starts with refs/heads/
. So refs/heads/master
represents branch master
, and so on.
A remote-tracking name is a reference whose full name starts with refs/remotes/
. The next part of the full name is the same as the name of the remote, and after that (and another slash) you get the branch name taken from the other Git.
This is the normal usage pattern for normal clones. There's some existing repository, which someone—or many someones—have set up somewhere out on the web (perhaps on GitHub, for instance), and it has a bunch of branches: master
, develop
, feature/A
, feature/B
, and so on. You clone that repository to your own machine (laptop or whatever) and would like to have your Git remember their branches for you, but not create a bunch of (local) branches. You now choose, perhaps, to do some work that you want to send to them later as a part of feature/A
, so you create your own name feature/A
on which to make new commits to send to them and recommend that they put those in their feature/A
. You're not working on feature/B
at all, so you don't get a feature/B
, and you're not using master
so you can delete your own master
.
Once you do have some new commits, you will use:
git push origin feature/A
to send your new commits to their Git, and immediately—as part of git push
itself—ask their Git to set their feature/A
branch to remember those new commits.
That's not what you want here
When you're first setting up centralized server repository, you often don't want to follow the normal pattern. You have—or would like to copy—some existing repository that has, say, a dozen branch names. If this repository isn't on your own laptop yet, you can use git clone --mirror
to make a temporary copy on your own laptop:
git clone --mirror <url> [<path>]
Now you have, on your laptop, a bare clone (--mirror
implies --bare
) that has no origin/*
remote-tracking names at all. Instead, Git has created, in your copy of their repository, regular old branch names—not remote-tracking names—corresponding to their branch names. So you have the same dozen branch names that they have.
A mirror clone is useless for doing any work of your own! You create this mirror clone temporarily, to get a copy of their repository in which their branch names are your branch names too. If you already have a full working repository with your dozen (or whatever) branches, you skip this step.
Now that you have the clone that has all the branches, now you can create an empty repository on the server (or on GitHub). Now you can run:
git push --all <url-of-server-repository>
And now, if you made a mirror clone, you can throw away the mirror clone. You made it only for the purpose of sending everything, including all the branch names, to the server. So now you might like to remove the mirror clone and make a normal clone of the server clone to use to do actual work.
(If you did a git push
from a local repository that was already all set, you don't want or need to remove the local clone, and you might want to use git remote add
before the git push
. See below.)
The above is somewhat wasteful!
You might object to having to make this silly mirror clone, only to then have to throw it out and make a normal, non-bare clone after pushing the mirror clone to the server.
You do not have to make the mirror clone. This is only for convenience.
Instead, you can:
- make a regular clone
- create local branches as needed to represent all the remote-tracking names
- use
git push --all
to send these all to the server
- remove all the local names you made (but keep any you didn't have to make).
Or, instead of the above, you can:
- make (or have) a regular clone
- use
git push
without --all
: instead, use refspecs to push the remote-tracking names on your end to branch names on their end.
This last method is in some ways the neatest, but it requires understanding refspecs.
A refspec is, in its second-simplest form, a pair of references—full names like refs/heads/master
or refs/remotes/feature/A
—separated by a colon :
. The name on the left side of the colon is the source and the name on the right side is the destination. Refspecs behave similarly, though not identically, in both git fetch
and git push
: the source ref provides a commit hash in the sending Git, and the destination ref provides a name to set in the receiving Git. Since git push
sends from your Git repository to their Git repository, you can use your remote-tracking names on the left, and their branch names on the right:
# after creating an empty repository on github
git remote add origin <url-on-github>
git push origin master # send your refs/heads/master to theirs
git push origin refs/remotes/savannah/devel-tomk:refs/heads/devel-tomk
git push origin refs/remotes/savannah/python_3:refs/heads/python_3
(assuming you want your remote-tracking savannah/devel-tomk
to become their devel-tomk
branch, and so on).
You can put all the refspecs into one big git push
line, but it's ridiculously easy to typo part of it, which is annoying:
git push origin master refs/remotes/savannah/devel-tomk:refs/heads/devel-tomk refs/remotes/savannah/python_3:refs/heads/python_3
for instance, if I did not typo anything.