1

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

master B - C - D

到这个?

master A - B - C - D

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

4

4 回答 4

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-DA。仍然打开时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您实际存储库中的复杂性。

于 2013-03-01T05:40:52.277 回答
1

您是否可以将 A 添加为新提交,然后将交互式重新设置为 B ( rebase -i B~1) 之前的提交,以按照您想要的方式重新排序提交?

于 2013-03-01T02:48:39.307 回答
1

是的,有一个警告。假设您从以下内容开始:

B - C - D

结果将是

A B C D'

请注意“主要”标记——B' 将具有与 B 相同的(内容),但由于其父级不同,它将具有不同的 SHA-1 哈希。

最简单的方法是使用移植物。创建一个同时包含 A 和 B 的存储库:

一种

B - C - D

请注意它们如何不相互连接。您通过“嫁接”( Wiki 页面)将它们彼此连接起来,这使 A 成为 B 的父...

一种
 \
  ...
     \
      B - C - D

我用了一条虚线,因为移植是暂时的。嫁接是通过编辑.git/info/grafts和写作创建的:

<B 的哈希值> <A 的哈希值>

使用以下命令使移植物永久化:

git filter-branch --tag-name-filter cat -- --all

这会将图表更改为:

A B C D'

使其永久化后,删除移植文件。

通常的警告适用——您正在重写历史记录,因此任何拉取您的存储库的人都必须使用git reset,只要他们没有本地更改。

于 2013-03-01T03:22:11.240 回答
0

简而言之,没有。

Git 中的每个提交都由一个哈希表示,“父”提交是哈希生成的元素之一。

因此,如果更改 B 的父级,则 B 将不再是 B(即哈希将不再相同)

您仍然可以通过使用 rebase 来做到这一点,即首先创建 A,然后在 A 上 rebase B、C、D...。但是,正如我之前所说,哈希将不再相同。如果这对你来说很好,那就继续吧:)

于 2013-03-01T03:06:31.957 回答