将新提交作为项目的旧版本

时间:2013-03-01 02:42:02

标签: git

在Git中,是否有可能做到这样的事情?

master B - C - D

到此?

master A - B - C - D

我使用Git的现有项目,一切都很顺利。但我发现该项目的旧版本,我希望将其提交给同一个回购,但将其作为A并使其看起来像是该项目的最早版本。是不是可以在Git中做到这一点?或者还有其他解决方法吗?

4 个答案:

答案 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 ......但是,正如我之前所说,哈希将不再相同。如果对你没问题,请继续这样做:)