如何创建一个新的(并且是空的!)“根”分支?


135

我想在这个git仓库中定义一个新的“ root”分支。“根”分支是指完全独立于存储库1中所有其他分支的分支。

不幸的是,即使在A回购的提交树的最底层的提交(我们称它为)也包含很多文件(这是在一个已经相当成熟的项目上初始化的存储库)。

这意味着即使我给出A了新分支的名称<start-point>,该新分支也不会从“干净的板岩”开始,而是将包含在中提交的所有文件A

有什么办法可以在此存储库中创建一个<start-point>尽可能接近的完全裸分支A


1 BTW,这等同于创建新的仓库。出于很多原因,单独的回购可能不太方便。


编辑:好的,这是我基于vcsjones的回答所做的:

# 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

尽管此过程涉及到一点点,但最终结果是一个空的基本提交,可以用作<start-point>任何新的“ clean-slate分支”。我要做的就是

git checkout -b cleanslate $(git rev-list --max-parents=0 HEAD)

将来,我将始终创建如下这样的新存储库:

git init
git commit --allow-empty -m 'base commit (empty)'

...因此第一次提交为,并且始终可用于启动新的独立分支。(据我所知,这是一种很少需要的工具,但是要使它易于使用非常容易。)



1
@Anonymoose:出于记录目的(而非辩论):我不同意您的意见。
kjo

1
似乎是基于一个更简单的解决方案git rebase --onto,请参阅stackoverflow.com/questions/645450/...
斯特凡纳·古里科

Answers:


222

--orphan在创建分支时使用:

git checkout --orphan YourBranchName

这将创建一个新的分支,上面有零个提交,但是所有文件都将被暂存。此时,您可以将其删除。
(“删除它们”:A git reset --hard将清空索引,而留下一棵空的工作树)

查看手册页以了解有关--orphan的更多信息。


这实际上是否会创建空白板?如从头开始?还是保留所有以前的更改,但不保留在git历史记录中?
Con Antonakos '16

4
@ConAntonakos这将创建一个没有父级的新分支。其他分支不受影响,所有更改都保留下来。
fuz

11

要添加到已接受的答案中,恢复到干净状态的最佳实践是创建一个初始的空提交,以便在为后代设置分支时可以轻松地进行基础调整。另外,由于您想要一个干净的状态,因此您可能已经提交了不应该提交的文件,因此必须从索引中删除它们。考虑到这些,您应该:

$ 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

1
我相信从2012年起这是没有必要的,因为您可以基于root
Timmmm


1

有什么办法可以在此存储库中创建一个完全裸的分支。

实际使用的命令(与Git 2.28+一起使用)是:

git switch --discard-changes --orphan newBranch
# or
git switch -f --orphan newBranch

git switch可从Git 2.23(2019年8月)中获得,并替换了旧的令人困惑的git checkout命令

但我建议使用Git 2.28(Q3 2020),因为git switch --discard-changes --orphan该版本已对其进行了优化。

参见brian m。的commit 8d3e33dcommit 8186128(2020年5月21日)。卡尔森(bk2204
(通过合并JUNIOÇ滨野- gitster-提交ded44af,2020年6月9日)

builtin/checkout:简化元数据初始化

签字人:brian m。卡尔森
评论者:德里克·斯托利

调用时init_checkout_metadatareset_tree,我们希望传递所涉及的提交的对象ID,以便可以将其传递给过滤器,如果没有提交,则可以传递给树。

我们预料到了后一种情况,这种情况可能会在结帐代码中的其他地方发生,但在这里不会发生。

唯一没有提交对象的情况是使用调用git switch--orphan

此外,我们只能使用--force或来在没有提交对象的情况下访问此代码路径--discard-changes

在这种情况下,用提交或树初始化结帐元数据没有意义,因为

  • (a)没有提交,只有空树,并且
  • (b)我们永远不会使用这些数据,因为在签出没有文件的分支时不会弄脏任何文件。

在这种情况下,传递全零对象ID,因为我们只需要一个有效的指针值即可。

测试:

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.