编辑git存储库的第一次提交未按预期工作

编辑git存储库的第一次提交未按预期工作,git,Git,我为培训创建了一个非常简单的git存储库。它有一个只包含初始提交的主分支,还有几个从主分支派生的分支。关键是我想编辑master指向的初始提交,以添加带有一些说明的自述文件,但在这样做之后,不是编辑第一次提交,而是创建一个新的提交,并更新master分支以指向它。我尝试了不同的策略:修改第一次提交,并使用-root选项交互地重定基址,但所有这些都会产生相同的结果 这是我的git日志: * e2c1de0 (origin/rerere-base, rerere-base) Add second l

我为培训创建了一个非常简单的git存储库。它有一个只包含初始提交的主分支,还有几个从主分支派生的分支。关键是我想编辑master指向的初始提交,以添加带有一些说明的自述文件,但在这样做之后,不是编辑第一次提交,而是创建一个新的提交,并更新master分支以指向它。我尝试了不同的策略:修改第一次提交,并使用-root选项交互地重定基址,但所有这些都会产生相同的结果

这是我的git日志:

* e2c1de0 (origin/rerere-base, rerere-base) Add second line to 
rerere/file.txt to provoke a conflict
* 58af1bf Add file.txt for rerere example
...
| * 91d8f5b (origin/bisect-run, bisect-run) Add new test for minus
| * c7db602 Intentionally add a failing commit
...
| * 4ffaae9 Add calculator class with sum method
| * 188e648 Create package skeleton
|/
* 1d44a36 (HEAD -> master, origin/master, origin/HEAD) Initial commit
这是编辑第一次提交后的结果:

* 60f5e5c (HEAD -> master) Initial commit
* e2c1de0 (origin/rerere-base) Add second line to rerere/file.txt to provoke a conflict
* 58af1bf Add file.txt for rerere example
...
| * 91d8f5b (origin/bisect-run) Add new test for minus
| * c7db602 Intentionally add a failing commit
...
| * 4ffaae9 Add calculator class with sum method
| * 188e648 Create package skeleton
|/
* 1d44a36 (origin/master, origin/HEAD) Initial commit
请注意,新的提交已与消息初始提交一起添加,其父级是e2c1de0 origin/rere base,而不是原始初始提交。 真奇怪,不是吗

有人能告诉我发生了什么,并提供一个理想的解决方案吗

上述原始存储库位于,以防有人想自己尝试

提前谢谢

编辑: 多亏@torek的回答,我才能够理解这里发生了什么。这个问题意味着两件事:

我知道,使用rebase编辑或终止以前的提交意味着重写历史并生成新的提交。然而,我认为依亲提交,例如,那些有它作为祖先的被正确更新,我恐怕不是这样的。 我使用git log with-oneline选项检查历史记录,这误导了我,因为我认为新生成的提交不是根提交,而是历史记录中前一个提交的子项,这是不正确的,如果显示历史记录而不使用-oneline选项,则可以检查它。 请参见下面的差异:

* commit 60f5e5c474719f2a6557859b04154c1b7a4d9e4b (HEAD -> master, origin/master, origin/HEAD)
  Author: ...
  ...
* commit e2c1de0a44be64e187a16a4e6bb380caef2343b7 (origin/rerere-base)
| Author: ...
| ...  
* commit 58af1bfce7a5a27143a3ca5dff464e004306c7f5
| Author: ...
| ...
...
这是正常的。任何更改提交的尝试实际上都会生成新的提交

更改提交在物理上是不可能的,因为提交的哈希ID是提交内容的加密校验和。如果使用不同的内容进行新的提交,则这是使用不同哈希ID的不同提交

git rebase就是这样工作的:它接受一整条现有提交链,并进行新的、改进的、不同的提交。然后重写用于定位最后一个旧提交的分支名称,以指向最后一个新提交。任何不知道旧提交的散列ID的人,只要使用该名称访问提交,就会看到新提交:而且似乎它们已经改变了

但是,任何仍然拥有原始提交哈希ID的人都会在旧ID下看到旧提交,因为它们仍然在存储库中

要让每个人都使用新提交,必须在将所有提交复制到新提交之后,为您试图更改但实际复制的提交的后代的每个提交重写所有名称。这是因为每个后续提交都包含其父级的哈希ID,因此需要将子级复制到具有新的不同父级的新提交中,然后复制子级以对其父级重新编号,依此类推

注意,不带-oneline的git log-graph将向您显示新提交是根提交。对于-oneline,很难说是这种情况,因为ASCII图形图形在同一列中只有两个*字符:

* <hash> new root commit
* <hash> tip of other branch
如果有更多的文本行,您将看到以下内容之间的差异:

* <hash> tip of some branch
|        that uses more than one
|        line in the output
|
* <hash> another commit
以及:

其他图形查看器gitk、GitGUI等绘制更好的图形线并使其更清晰,但很少出现这样的多个根

1好吧,并非完全不可能:如果发现散列冲突,例如,可以使用一个散列ID进行两次不同的提交。但是,由于Git的内部设置,如果新对象具有相同的散列ID,则无法替换旧对象,因此即使在这种情况下也无法更改提交。您可以仔细构造两个独立的存储库,一个具有冲突ID的提交,另一个具有相同ID的其他不同提交。

解决方案 我想编辑master指向的初始提交,以添加一个自述文件,并附带一些说明

将新文件添加为新提交

如果你需要它在多个分支,合并或樱桃选择

修改公共承诺-只是不要这样做。 国家:

-修正。。。 如果您修改了已发布的提交,您应该了解重写历史的含义。请参阅git REBASE中的“从上游REBASE恢复”部分

对其他人基于其工作的分支进行重定基址或任何其他形式的重写都是一个坏主意:它下游的任何人都必须手动修复其历史记录

如果您有疑问,这里还有另一条信息:

不要修改公开声明

修改后的提交实际上是完整的 y新提交和上一次提交将不再在当前分支上。这与重置公共快照的后果相同。避免修改其他开发人员基于其工作的提交。对于开发人员来说,这是一个令人困惑的情况,而且恢复起来也很复杂


首先,谢谢你的回复。我完全理解结束提交意味着创建新的提交并重写历史。然而,我认为每个依赖于它的提交(在本例中,将其作为其父级的提交)都会进行属性更新,但情况似乎并非如此。带有oneline的Git日志误导了我,因为我认为新创建的提交不是根提交,而是图中前一个提交的子提交。现在我明白了。谢谢
* <hash> new root commit
         with more than one line

* <hash> tip of some branch
...