home of the madduck/ blog/
Creating a git branch without ancestry

Robin Rosenberg introduced me to the simplest method of creating a new git branch without any ancestors:

$ echo ref: refs/heads/newbranch > .git/HEAD
$ git branch
  master
[...]
$ git commit -m 'creating newbranch'
$ git branch
  master
* newbranch

This comes in handy if you want to maintain two separate components without any common files in the same repository. I am using it currently while experimenting with a new method of storing my home directory in git, which is still far from anywhere. I shall report once I reach a point of success or failure.

NP: Rush: Moving Pictures

Update: Johannes Schindelin taught me how to do the same without touching files in .git/:

$ git symbolic-ref HEAD refs/heads/newbranch
[...]

and also addressed the issue which would have all files already committed to the "master" branch now appear in the git status output as staged.

This is because the index contains the full copy of a revision of a file, as it would be if committed at any point. git status shows the differences between what has been committed, what would be committed, and what is available in the working tree. Since we pointed HEAD to nowhere ("newbranch" does not yet exist), the index and what has been committed (nothing in this case) diverge, the files are still staged, and thus are scheduled to be part of the impending commit.

The way to fix this is to remove the index:

$ rm .git/index

This may seem weird, but it works, because git recreates the index whenever you switch branches:

piper:~> git init-db
Initialized empty Git repository in .git/
piper:~> echo 1 > a; git add a; git commit -m.
Created initial commit e774324: .
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 a
piper:~> git symbolic-ref HEAD refs/heads/newbranch
piper:~> rm .git/index
piper:~> git status
# On branch newbranch
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       a
nothing added to commit but untracked files present (use "git add" to track)
piper:~> echo 2 > b; git add b; git commit -m.
Created initial commit 54ff342: .
1 files changed, 1 insertions(+), 0 deletions(-)
create mode 100644 b
piper:~> git branch
  master
* newbranch
piper:~> git checkout master
fatal: Untracked working tree file 'a' would be overwritten by merge.
piper:~> git checkout -f master

Switched to branch "master"
piper:~> git status
# On branch master
nothing to commit (working directory clean)
piper:~> ls
a
piper:~> git checkout newbranch
Switched to branch "newbranch"
piper:~> git status
# On branch newbranch
nothing to commit (working directory clean)
piper:~> ls
b

As you can see, the creation of the branch is a bit complex, but once you (forcefully) switched back to master, you can then freely switch between and commit to them.