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

时间:2018-10-22 21:09:44

标签: git

我有一个非常简单的git存储库,它是为培训而创建的。它有一个仅包含初始提交的master分支,以及几个从master植根的分支。关键是我想编辑初始提交(由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

请注意,新的提交已添加,消息为Initial commit,其父级为e2c1de0 (origin/rerere-base),而不是原始的初始提交。 真的很奇怪,不是吗?

有人可以解释一下发生了什么,理想情况下可以提供解决方案吗?

前面提到的原始存储库位于https://github.com/beni0888/gitlikeapro,以防万一有人想自己尝试。

谢谢!

编辑: 感谢@torek的回答,我已经能够了解这里发生了什么。这个问题暗示两件事:

  • 我知道使用rebase修改或编辑以前的提交意味着重写历史记录并生成一个新的提交。但是,我认为从属提交(例如,将其作为祖先提交的)已正确更新,恐怕不是这样。
  • 我当时使用的是带有--oneline选项的git log来检查历史记录,这使我产生了误解,因为我认为新生成的提交不是根提交,而是历史上上一个提交的孩子,这是不正确的,如果您显示的历史记录没有--oneline选项,则可以进行检查。

请参见以下区别:

* commit 60f5e5c474719f2a6557859b04154c1b7a4d9e4b (HEAD -> master, origin/master, origin/HEAD)
  Author: ...
  ...
* commit e2c1de0a44be64e187a16a4e6bb380caef2343b7 (origin/rerere-base)
| Author: ...
| ...  
* commit 58af1bfce7a5a27143a3ca5dff464e004306c7f5
| Author: ...
| ...
...

2 个答案:

答案 0 :(得分:1)

这是正常现象。 任何尝试更改提交的尝试实际上都会产生一个新的提交。

更改提交实际上是不可能的 1 ,因为提交的哈希ID是提交内容的加密校验和。如果您进行具有不同内容的新提交,则这是具有不同哈希ID的不同提交。

这就是git rebase的工作方式:它需要整个现有提交链,并从中进行新的,改进的,不同提交。 分支名称(用于查找旧的迟钝提交的最后一个),然后被重写以指向闪亮的新提交的最后一个。任何不知道旧提交的哈希ID,仅使用 name 来访问提交的人,都会看到新提交:好像它们已更改。

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

要使每个人都可以使用新的提交,对于每个“之后”的提交(后代),必须将 all 的提交复制到新的提交之后,重写 all 的名称。 -from)您尝试更改但实际上已复制的那一。这是因为每个后续提交都包含其父级的哈希ID,因此您需要将子级复制到具有新的父级且不同的父级的新提交中,然后复制该子级的子级以对父级重新编号,等等。

请注意,git log --graph --oneline将向您显示新提交是根提交。使用--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

和:

* <hash> new root commit
         with more than one line

* <hash> tip of some branch
...

其他图形查看器(gitk,git-gui等)绘制出更好的图形线并使之更清晰,但是很少有像这样的多重根出现的。


1 好吧,不是 quit 不可能:如果您发现哈希冲突(例如,请参见https://shattered.it/),则可以进行两个不同的提交,每个提交只有一个哈希ID。但是,由于Git的内部设置,如果您的新对象具有相同的哈希ID,则无法替换,因此即使在以下情况下,也无法更改:这个案例。您可以做的是仔细构造两个单独的存储库,一个存储库的一个提交具有冲突的ID,另一个存储库的另一个提交具有相同的ID。

答案 1 :(得分:0)

解决方案

  

我想编辑初始提交(由主控点指向)以添加一些说明的自述文件

将新文件添加为新提交。

如果您需要多个分支,请合并或选择。


修订公共承诺-只是不要这样做。

Git doco状态:

  

-修改(...)   如果您修改已经发布的提交,则应该了解重写历史的含义。 (请参阅git-rebase中的“从UPSTREAM REBASE恢复”部分。)

RECOVERING FROM UPSTREAM REBASE状态

  

让其他人基于其工作的分支重新建立基础(或进行任何其他形式的重写)是一个坏主意:该分支下游的任何人都必须手动修复其历史记录。

如有疑问,您在这里还有另一则消息a tutorial

  

不修改公共承诺

     

修订的提交实际上是全新的提交,以前的提交将不再位于您的当前分支上。这具有与重置公共快照相同的结果。避免修改其他开发人员基于其所做的提交。对于开发人员来说,这是一个令人困惑的情况,并且要从中恢复很复杂。