0

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 - ...
Roy
  • 418
  • 2
  • 16
  • What happens when you try? It's about 10x faster to test it than to write your question. – Jonathan Hall May 25 '18 at 08:07
  • @Flimzy I don't know how to do this. – Roy May 25 '18 at 08:36
  • Then you need to learn the basics of git. In particular: how to init a repo, and how to create a branch. But you'll need to know both of those things anyway--and your question makes it sound like you already know these things. – Jonathan Hall May 25 '18 at 08:37
  • 1
    Do you need to keep identity of commits on v2.0 branch? If so, it can't be done. Otherwise, it's a rebase. – Frax May 25 '18 at 08:39
  • @Frax yes I want to keep everything intact in v2.0(master) branch, so there is no solution here. – Roy May 25 '18 at 08:42
  • If you mean *prepend* new history *before* the existing history *without* rewriting the existing history, then no. Doing what your graph shows includes rewriting the history of the `v2.0` branch. – Lasse V. Karlsen May 25 '18 at 14:18

1 Answers1

2

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.

torek
  • 448,244
  • 59
  • 642
  • 775