I have a git repo that has source code of program v2.0 as initial import, like
v2.0(master) - o - o - ...
Can I create a branch of v1.0 code before v2.0 initial import commit? like:
v1.0 - o - o - ...
\
v2.0(master) - o - o - ...
I have a git repo that has source code of program v2.0 as initial import, like
v2.0(master) - o - o - ...
Can I create a branch of v1.0 code before v2.0 initial import commit? like:
v1.0 - o - o - ...
\
v2.0(master) - o - o - ...
The short answer is no.
The long answer is instructive: in Git, a branch name is simply a pointer to a commit. This means that, regardless of what you mean by "branch"—see What exactly do we mean by "branch"?—you can't have a branch that does not have at least one commit on it.
Moreover, this drawing is fundamentally wrong:
v2.0(master) - o - o - ...
It implies that the branch name sits at the left and new commits grow, one at a time, to the right. It's true that new commits do grow, one at a time, to the right—but the branch name sits at the right as well! That is, the name master
initially points to the very first commit you make. You start out with a completely empty repository:
master (HEAD)
The name HEAD
exists and is attached to a branch name, master
, but the branch itself does not exist because there are no commits!1 A branch name must point to an existing, valid commit, and there simply aren't any.
Eventually, you make your very first commit, and Git immediately makes the name master
point to it. The commit has some big ugly hash ID, which is in fact a cryptographic checksum of the contents of that commit —it depends on your name and email address, all the files that are stored under that commit, and the date-and-time, making it essentially impossible to predict—but let's just call it A
:
A <-- master (HEAD)
Then, some time later, you make a new commit. We'll call it B
here. New commit B
records the actual hash ID of commit A
, so we say that B
points to A
:
A <-B
What happens to the branch name at this point is the key. The name master
stops pointing to commit A
because Git immediately overwrites master
with the new hash ID of new commit B
:
A <-B <-- master (HEAD)
At this point, if you create a new branch name, you do so by setting it to point to one of these two existing commits. You can then attach the name HEAD
to it:
A <-B <-- master, xyz (HEAD)
and now if you make a new commit—let's call it C
—the new commit will point back to B
and Git will write C
's hash ID into whichever name has HEAD
attached to it:
A <-B <-- master
\
C <-- xyz (HEAD)
Note that commit A
will never point to any other commit: commits, once made, are read-only. Commit A
has no parent and it will remain that way forever.
(You can, at any time, make a whole series of new and different commits, and Git will let you change all branch names to point to a completely new and different set of commits, so you could go in and create:
G--H--I <-- branch-for-v1
\
J--K--L <-- master (HEAD)
leaving commits A-B-C
behind forever, and eventually those three commits expire and are removed—but this doesn't change commits A-B-C
, which are still identified by their actual hash IDs, whatever those may be. The general term for this idea—of making whole new chains of commits, then making the branch names point to the new chains instead of the old chains—is called rewriting history. If and when the concept works, it does so because we humans just start with whichever commit the name points to, and, just like Git, work our way backwards, through these backwards-pointing internal commit arrows.)
1This means that if you ask Git which branch you're on (git status
will tell you for instance), it will say master
, but if you ask Git which branches exist, it will tell you that no branches exist. You are literally on a branch that does not exist. Git variously calls this an unborn branch or an orphan branch. The former is, at least in my opinion, actually the better name for it; the name "orphan branch" is a mistake that we're stuck with because someone goofed early on in Git's development.