2

我正在为一本书编写一个示例应用程序。

每个重要的提交都被标记(例如 Ch01_Ex04、Ch03_Ex01),以便读者可以直接了解他们感兴趣的应用程序的状态。

我时不时地改变我在示例中所做的事情的想法,我想回到过去并改变,例如,类名。我希望从给定的提交中应用该更改,而无需重置所有标签。

说我有:

 Tag1    Tag2    Tag3
  |       |       |
- A - B - C - D - E
                  |
                 HEAD

现在我想在 B 和 C 之间进行更改,所以我从 B 分支并进行更改,我有:

 Tag1    Tag2    Tag3
  |       |       |
- A - B - C - D - E
       \          |
        F        HEAD

我想要的是:

 Tag1        Tag2    Tag3
  |           |       |
- A - B - F - C - D - E
                      |
                     HEAD

我无法理解如何做到这一点。有办法吗?

4

2 回答 2

3

我想回到过去并更改例如班级名称。我希望从给定的提交中应用该更改,而无需重置所有标签。

 Tag1    Tag2    Tag3
  |       |       |
- A - B - C - D - E
                  |
                 HEAD

我想要的是:

 Tag1        Tag2    Tag3
  |           |       |
- A - B - F - C - D - E
                      |
                     HEAD

Git 最有力的保证是没有人能做到这一点

根本不可能(“因为数学”,特别是加密哈希函数背后的数学)将提交插入历史或对历史进行任何其他更改,而每个人都无法立即检测到修改过的历史。

你能得到的最接近的是

 Tag1        Tag2    Tag3
  |           |       |
- A - B - F - C*- D*- E*
                      |
                     HEAD

其中C*, D*, 和E*是看起来几乎完全一样 C的新提交, D, E-- 相同的提交消息、作者、日期等等,除了它们的哈希码。这意味着必须重置标签。git 并没有竭尽全力使这种规模的重写变得容易。

@Joe 链接的答案将向您展示如何在 filter-branch 完成重写历史记录后移动任何孤立标签,假设您走那条路线。

但我建议你考虑一个不同的解决方案来解决你的问题。

据我了解,您希望人们能够轻松找到例如“Ch01_Ex04”的当前版本,但随着写作的进行,这些可能会发生变化。完全合理的东西。问题是,标签不是正确的解决方案。它们的存在是为了识别特定的、固定的历史内容分布。

您想要什么,识别当前扮演特定角色的内容的提交,最好通过将状态直接放在提交消息本身中来实现,而不是通过其标签名称引用提交,而是通过该内容来识别它:例如git show':/^===Ch01_Ex04==='将显示消息开始的当前分支上的最新提交===Ch01_Ex04===

于 2014-04-26T07:52:37.297 回答
0

要修改历史上更早的提交,您必须使用更复杂的工具。Git 没有修改历史工具,但您可以使用 rebase 工具将一系列提交 rebase 到它们最初基于的 HEAD 上,而不是将它们移动到另一个。使用交互式 rebase 工具,您可以在每次提交后停止您想要修改和更改消息、添加文件或做任何您想做的事情。您可以通过将-i选项添加到git rebase. 您必须通过告诉命令要重新定位到哪个提交来指示要重写提交的时间。

例如,如果您想更改最后三个提交消息,或该组中的任何提交消息,您将作为参数提供给git rebase -i您要编辑的最后一个提交的父级,即HEAD~2^or HEAD~3。可能更容易记住,~3因为您正在尝试编辑最后三个提交;但请记住,您实际上是在指定四个提交之前,即您要编辑的最后一个提交的父级:

$ git rebase -i HEAD~3

用于重写历史的源git 文档

于 2014-04-25T20:05:23.040 回答