How to create a new (and empty!) "root" branch?
GitGit Problem Overview
I would like to define a new "root" branch in this git repository. By "root" branch I mean a branch that is entirely independent of all the other branches in the repository1.
Unfortunately, even the commit (let's call it A
) at the very base of the repo's commit tree contains a lot of files (this was a repository that was initialized on an already fairly mature project).
This means that even if I gave A
as the new branch's <start-point>
, this new branch would not start from a "clean slate", but rather it would contain all the files that were committed in A
.
Is there some way I can create a completely bare branch in this repository, with <start-point>
as close to A
as possible?
1BTW, this is not equivalent to creating a new repo. Separate repos would be less convenient for a lot of reasons.
EDIT: OK, this is what I did, based on vcsjones' answer:
# save rev of the current earliest commit
OLDBASE=$(git rev-list --max-parents=0 HEAD)
# create a new orphan branch and switch to it
git checkout --orphan newbranch
# make sure it's empty
git rm -rf .
# create a new empty commit in the new branch, and
# save its rev in NEWBASE
git commit --allow-empty -m 'base commit (empty)'
NEWBASE=$(git rev-list HEAD)
# specify $NEWBASE as the new parent for $OLDBASE, and
# run filter-branch on the original branch
echo "$OLDBASE $NEWBASE" > .git/info/grafts
git checkout master
git filter-branch
# NOTE: this assumes that the original repo had only one
# branch; if not, a git-filter-branch -f <branch> command
# need to be run for each additional branch.
rm .git/info/grafts
Although this procedure is a bit involved, the end result is an empty base commit that can serve as the <start-point>
for any new "clean-slate branch"; all I'd need to do then is
git checkout -b cleanslate $(git rev-list --max-parents=0 HEAD)
In the future I will always create new repositories like this:
git init
git commit --allow-empty -m 'base commit (empty)'
...so that the first commit is empty, and always available for starting a new independent branch. (This would be, I know, a very rarely needed facility, but it is quite effortless to make it readily available.)
Git Solutions
Solution 1 - Git
Use the --orphan
when creating the branch:
git checkout --orphan YourBranchName
This will create a new branch with zero commits on it, however all of your files will be staged. At that point you could just remove them.
("remove them": A git reset --hard
will empty the index, leaving you with an empty working tree)
Take a look at the man page for checkout for more information on --orphan.
Solution 2 - Git
To add to the accepted answer - best practice to revert to clean state is to create an initial empty commit so you can easily rebase while setting up your branches for posterity. Plus since you want a clean state you probably have committed files that you shouldn't, so you have to remove them from the index. With those in mind you should:
$ git checkout --orphan dev2
Switched to a new branch 'dev2'
$ git reset # unstage all the files, you probably don't want to commit all of them
$ git commit --allow-empty -m 'Initial empty commit'
[dev2 (root-commit) a515c28] Initial empty commit
Solution 3 - Git
> Is there some way I can create a completely bare branch in this repository.
The actual command to use (with Git 2.28+) is:
git switch --discard-changes --orphan newBranch
# or
git switch -f --orphan newBranch
git switch
is available from Git 2.23 (August 2019), and replaces the old confusing git checkout
command.
But I would recommend Git 2.28 (Q3 2020), because git switch --discard-changes --orphan
has been optimized in that version.
See commit 8d3e33d, commit 8186128 (21 May 2020) by brian m. carlson (bk2204
).
(Merged by Junio C Hamano -- gitster
-- in commit ded44af, 09 Jun 2020)
> ## builtin/checkout
: simplify metadata initialization
> Signed-off-by: brian m. carlson
> Reviewed-by: Derrick Stolee
> When we call init_checkout_metadata
in reset_tree,
we want to pass the object ID of the commit in question so that it can be passed to filters, or if there is no commit, the tree.
> We anticipated this latter case, which can occur elsewhere in the checkout code, but it cannot occur here.
> The only case in which we do not have a commit object is when invoking git switch
with --orphan
.
> Moreover, we can only hit this code path without a commit object additionally with either --force
or --discard-changes
.
> In such a case, there is no point initializing the checkout metadata with a commit or tree because
> - (a) there is no commit, only the empty tree, and
- (b) we will never use the data, since no files will be smudged when checking out a branch with no files.
> Pass the all-zeros object ID in this case, since we just need some value which is a valid pointer.
Test:
git switch master
echo foo >foo.txt
git switch --discard-changes --orphan new-orphan2
git ls-files >tracked-files
# test_must_be_empty tracked-files
Solution 4 - Git
If you use git 2.23 or above you may be used to git switch
and git restore
instead of git checkout
. If so, the flag is the same as mentioned in this answer.
git switch --orphan YourBranchHere