Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create an empty branch?

Tags:

git

I have a git repo containing a project. I now am going to do a massive overhaul of the project.

How can I create a new branch for this overhaul that is blank? Then when complete. How can I switch this branch to master?

like image 395
panthro Avatar asked Jun 13 '16 14:06

panthro


2 Answers

use the checkout --orphan command

git checkout --orphan MyNewBranch
git reset -- *
git ls-files

see also this link https://git-scm.com/book/en/v2/Git-Tools-Replace

like image 193
Gregg Avatar answered Nov 13 '22 11:11

Gregg


Gregg's answer and the linked possible-duplicate both suggest using git checkout --orphan (the linked question dates back to when --orphan was relatively new).

In a comment, exxecc suggested creating a branch from some existing commit, deleting all the contents (e.g., git rm -r .), and going on from there.

Both methods are valid and workable. So which one should you use? The answer to that depends not on what you want to do right now, but rather what you want to do and see later. The key is, as usual, Git's commit graph. (To spoil the effect somewhat, but be more useful as an answer, I'd say "go with orphan" since you may need to defer this decision, and "orphan" gives you more options later. Read on to see what I am talking about.)

An orphan branch is a new root commit

When you view Git's commit graph,git log starts with the current commit by default, or the tip-most commit of any named branch. (Then it goes on to ruin this sensible behavior by sorting commits by date, but that's a different problem, and if the dates themselves are sensible, this "ruining" has basically no effect and it's actually all still sensible.) Hence we start with the current, or most recent on some branch(es), commits, and work backwards in time to a root commit.

A root commit is simply a commit with no parents. It is a starting point in time. It has descendents—commits that come after it, that are derived from it—but it has no ancestors. It was created from scratch; it has no preceding history.

This may be true of a rewrite (massive overhaul, in the original problem description).

Or, it may not. Sure, it's a rewrite—but there was something before. There were previous commits. Maybe you should include them.

Any other commit has history

If you make, as a non-root commit, a commit that empties out the previous version (and has nothing at all, or a simple skeleton, or perhaps even a new, rewritten implementation), you will, in the future, be able to scan back in time, to a point before this fresh start. That will, in fact, be more accurate. Moreover, it will allow you to merge this into other branches, with Git showing you conflicts for files modified or created since the "fresh start" point.

Suppose, for instance, that the project in question has one major branch, and this is the one you intend to rewrite, but it also has one side branch for some experimentation. If that experimentation proves successful, it might be nice, some time later, to bring some or all of that work back into the rewrite as well. If your rewrite starts by emptying things out and then replacing, a simple git merge of the experimental branch will give you conflicts of the form "modified by them, deleted by us" for each file with changes in it.

In any case, git log will be able to show you the true history: that, at some point, you did this massive rewrite. That true history may have some value. (Though, as is true of all code history, sometimes the value may be more negative than positive. :-) )

Getting the best of both worlds

Despite the possible advantages I suggest above for not using an orphan branch, I recommend the orphan branch method. The reason is that this lets you defer the decision. Here is the basic idea.

In the new orphan branch, which has a completely independent history—incidentally, you can make this in a completely independent repository as well, obviating the need for git checkout --orphan—you can develop the overhauled, rewritten version from scratch. Then, at some point, you deem it ready for replacing the old version. At this point, you can merge the two branches (or the two repositories) even though they have no common base. You simply need to make a new commit with two parents: the first parent is the current tip of the rewritten branch, and the second parent is the original (un-rewritten) version.

This second parent commit can either be the original version as it stands now, at the point the two are being "merged", or a commit as of the time the rewrite project started.

I put "merged" in quotes here only because the tree for the merge commit will simply be the rewrite version. We will ignore the old version's source entirely. The point of the new merge commit is simply to join up the histories of the two lines of development, and to imply (by making the branch name, master for instance, point to the new merge commit) that the new version is now in charge, as it were.

(This kind of merge is made by the -s ours strategy, although there is a relatively easy way to make it manually as well. If you want to make this merge directly on master you will need the equivalent of -s theirs instead, which requires the manual method. To do it with -s ours, make the merge on the orphan branch, then shuffle branch names around. If you have put the new orphan-branch version in an orphan—separate—repository, simply add the new repository as an extra remote, fetch the new version, and then make the merge commit as usual.)

like image 18
torek Avatar answered Nov 13 '22 12:11

torek