在Git中,是否有可能做到这样的事情?
master B - C - D
到此?
master A - B - C - D
我使用Git的现有项目,一切都很顺利。但我发现该项目的旧版本,我希望将其提交给同一个回购,但将其作为A并使其看起来像是该项目的最早版本。是不是可以在Git中做到这一点?或者还有其他解决方法吗?
答案 0 :(得分:2)
是的,这很容易做到,但我会从标准警告开始,知道它会将B-C-D
更改为B'-C'-D'
,也就是说,它们会有新的提交哈希值将与存储库的任何现有克隆发生冲突。假设你那么好......
我们首先要了解git被组织为一系列提交,每个提交都有一个指向其父级的指针。通过这种方式,可以创建提交树。
tree 1: B - C - D
因为你想要做的是在第一次提交之前添加一些东西 - 并且在第一次提交之前没有什么要解决的 - 我们必须创建一个新树来执行此操作。
要创建新树,我们将从空提交开始。将空提交作为存储库的第一次提交会使这样的事情变得更容易。这是通过以下命令完成的(添加的数字供以后参考)
git checkout --orphan new-branch (1)
git rm -r --force --cached . (2)
git clean -fd (3)
git clean -fd (3a)
git commit --allow-empty -m 'Initialize' (4)
这将创建一个未连接到任何其他分支的新分支(1)。这使得工作目录中的所有文件都被缓存并准备好提交。我们不想提交这些文件,因此(2)将它们从缓存中删除; while(3)将它们从目录中删除。有时需要清理两次,因为忽略的文件不会被清除,但.gitignore文件会 - 需要再次清理文件。
最后,(4)创建一个空提交作为此分支中的第一个提交。 --allow-empty
参数使这成为可能 - 任何消息都可以。
现在,添加项目早期版本的所有文件A
和提交。
git add .
git commit -m 'A'
------------------
tree 1: B - C - D
tree 2: A
我们已准备好将B-C-D
移至A
。在new-branch
时,此命令将移动它们。
git rebase -i --onto new-branch --root D
这将结帐D
,将树(回放)返回到根B
并按顺序将每个提交移至A
- 每次执行新提交方式直到它回到D
。 注意:您很可能会遇到合并冲突,请准备好处理它们。
完成后,树看起来像这样
tree 1: <empty> <-- this will be garbage collected in time
tree 2: A - B' - C' - D'
此时,请回到您可能拥有的任何远程存储库 - 您需要强制推送
git push --force <remote> <local-branch>:<remote-branch>
这将覆盖远程分支 - 确保这是您想要的。
这就是它的全部。只记得不要处理你唯一的存储库副本,这样你就可以重新克隆,如果它被打结就再试一次。除此之外,我建议您阅读git rebase ...
,以便熟悉正在发生的事情 - 以及您可能遇到的怪癖,具体取决于您实际存储库中B-C-D
的复杂程度。
答案 1 :(得分:1)
您可以将A添加为新提交,然后在B(rebase -i B~1
)之前将交互式重新绑定到提交,以便按照您想要的方式对提交进行重新排序吗?
答案 2 :(得分:1)
是的,请注意。我们假设您从:
开始B - C - D
结果将是
A - B' - C' - D'
请注意,“prime”标记-B'将具有与B相同的树(内容),但它将具有不同的SHA-1哈希,因为其父级不同。
最简单的方法是使用移植物。创建一个包含A和B的存储库:
A B - C - D
请注意它们之间没有相互连接的方式。你用“移植”(Wiki page)将它们相互连接起来,这使得A成为B的父...
A \ ... \ B - C - D
我使用虚线,因为移植物是暂时的。通过编辑.git/info/grafts
并撰写:
<hash of B> <hash of A>
使用以下命令使移植物永久化:
git filter-branch --tag-name-filter cat -- --all
这会将图表更改为:
A - B' - C' - D'
将其永久化后,删除移植文件。
通常的警告适用 - 您正在重写历史记录,因此任何拔出您的存储库的人都必须使用git reset
,只要他们没有本地更改。
答案 3 :(得分:0)
简而言之,没有。
Git中的每个提交都由哈希表示,“父”提交是哈希生成的元素之一。
因此,如果您更改B的父级,B将不再是B(即哈希将不再相同)
你仍然可以通过使用rebase来实现,你可以在A上创建A,并在A上创建B,C,D ......但是,正如我之前所说,哈希将不再相同。如果对你没问题,请继续这样做:)