tags:

views:

245

answers:

4

While helping a friend with a git problem today, I had to introduce a branch that needed to be totally separate from the master branch. The contents of this branch really had a different origin from what had been developed on the master branch, but they were going to be merged into the master branch at a later time.

I remembered from reading John Wiegley's Git from the bottom up how branches are essentially a label to a commit that follows a certain convention and how a commit is tied to a tree of files and, optionally to parent commits. We went to create a parentless commit to the existing repository using git's plumbing:

So we got rid of all files in the index ...

$ git rm -rf .

... extracted directories and files from a tarball, added those to the index ...

$ git add .

... and created a tree object ...

$ git write-tree

(git-write-tree told us the sha1sum of the created tree objact.)

Then, We committed the tree, without specifying parent commits...

$ echo "Imported project foo" | git commit-tree $TREE

(git-commit-tree told us the sha1sum of the created commit object.)

... and created a new branch that points to our newly created commit.

$ git update-ref refs/heads/other-branch $COMMIT

Finally, we returned to the master branch to continue work there.

$ git checkout -f master

This seems to have worked as planned. But this is clearly not the kind of procedure I would recommend to someone who is just getting started using git, to put it mildly. Is there an easier way of creating a new branch that is entirely unrelated to everything that has happened in the repository so far?

+9  A: 

From Git Community Book:

git symbolic-ref HEAD refs/heads/newbranch 
rm .git/index 
git clean -fdx 
<do work> 
git add your files 
git commit -m 'Initial commit'
Artem Tikhomirov
This is a great answer.
gahooa
+3  A: 

Github has a feature called Project Pages where you can create a particular named branch in your project to provide files that will be served by Github. Their instructions are as follows:

$ cd /path/to/fancypants
$ git symbolic-ref HEAD refs/heads/gh-pages
$ rm .git/index
$ git clean -fdx

From there you have an empty repository which you can then add your new content to.

Greg Hewgill
+4  A: 

Although the solution with git symbolic-ref and removing index works, it might be conceptually cleaner to create new repository

$ cd /path/to/unrelated
$ git init
[edit and add files]
$ git add .
$ git commit -m "Initial commit of unrelated"
[master (root-commit) 2a665f6] Initial commit of unrelated
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 foo

then fetch from it

$ cd /path/to/repo
$ git fetch /path/to/unrelated master:unrelated-branch
warning: no common commits
remote: Counting objects: 3, done.
Unpacking objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
From /path/to/unrelated
 * [new branch]      master     -> unrelated-branch

Now you can delete /path/to/unrelated

Jakub Narębski
In my opinion, a clean concept would involve an option to `git branch` or `git checkout`. I'm glad that git makes this sort of stuff possible, but why shouldn't it be easier?
hillu
Because it is, and should be a rare thing. If you have unrelated things branch, it usually belongs to unrelated repository, instead of stuffing it in existing one (although there are exceptions).
Jakub Narębski
A: 

Found this script at http://wingolog.org/archives/2008/10/14/merging-in-unrelated-git-branches and it works very fine !

#!/bin/bash

set -e

if test -z "$2" -o -n "$3"; then
    echo "usage: $0 REPO BRANCHNAME" >&2
    exit 1
fi

repo=$1
branch=$2

git fetch "$repo" "$branch"

head=$(git rev-parse HEAD)
fetched=$(git rev-parse FETCH_HEAD)
headref=$(git rev-parse --symbolic-full-name HEAD)

git checkout $fetched .

tree=$(git write-tree)

newhead=$(echo "merged in branch '$branch' from $repo" | git commit-tree $tree -p $head -p $fetched)
git update-ref $headref $newhead $head
git reset --hard $headref
Benoît
I believe that the same effect can be achieved using `git fetch $REMOTE $REMOTE_BRANCH:$LOCAL_BRANCH`. Am I missing something?
hillu