这个问题存在一种基本错误,因为它假设只有一个根提交。事实上,“rootness”是提交的一个属性:当且仅当它没有父提交时,提交才是根提交。
每当您使用 git commit 进行新提交时,Git 都会使该新提交使用 当前 提交的哈希 ID 作为其(第一个,通常也是唯一的)父提交。
作为一种特殊情况——在一个新的、完全空的、还没有提交的存储库中是必需的——Git 允许你在它所调用的地方,不同地,一个未出生的分支或一个孤儿分支。 “孤儿”一词是出现在git checkout 和git switch 命令中的词:
git checkout --orphan new-branch
和:
git switch --orphan new-branch
例如。不过,“未出生”形容词可能是更高级的形容词,因为它描述了处于此模式时的实际状态:这两个命令实际上根本没有创建新分支。当你处于这种模式时,你在一个不存在的分支上!
在这种模式下——当你在一个未出生的分支上——git commit 命令将创建一个新的 root 提交,即一个没有父级的提交。这个新的根提交的创建导致分支出现,新的分支名称现在标识新的根提交。因此,实现您想要的结果的一种方法是:
git checkout master # if needed; use main if appropriate, etc
git checkout --orphan new
git commit
然后将旧的master 或main 重命名,或将其完全删除,然后将new 重命名为master 或main。
这使用了一些技巧,我将在下一段中描述,并达到与William Pursell's answer 相同的结果,这也很好。请注意,您必须在此处使用git checkout --orphan,而不是git switch --orphan,这是诀窍的一部分。
这里的诀窍是 git commit 从 Git 的 index 中的任何内容构建新提交。 git checkout --orphan 命令不会触及 Git 的索引,所以索引中的内容是刚才在您运行git checkout --orphan 之前索引中的内容。这就是为什么我们可能需要一个初始的 git checkout master 或 git checkout main: 来填写 Git 的索引(和你的工作树)。
git switch --orphan 命令具有清空 Git 的索引(以及您的工作树)的副作用。因此,这对于创建一个新的 empty 提交很有用:它不会重用 current 提交中的文件。 git checkout --orphan 命令不会清空 Git 的索引,因此它可以很好地创建与当前提交完全匹配的新提交。由于这两种命令都不是人们每天都在使用的,因此这些微妙之处可能会被忽视。
大多数存储库可能只有一个根提交。任何非空(和非浅1)存储库都有至少一个根提交,但根提交的数量仅受提交总数的限制。
1浅层克隆是一种忽略非浅层 Git 存储库中的一个或多个提交的提交,这些提交是这些提交的最终来源。为此,Git 插入了一个标记“graft points”的文件,并且不打扰他们的父母。生成的提交有父提交,但 Git 的某些部分假装它们没有,所以这些浅移植点既可以作为根提交,也可以作为非根提交,具体取决于哪些代码试图对它们做什么。但是,除了使用浅层存储库来节省空间和/或节省时间之外,最好忽略这种复杂性。