git rebase -i --为什么它要改变提交哈希?

eblbsuwk  于 2023-04-28  发布在  Git
关注(0)|答案(6)|浏览(159)

所以我或多或少熟悉rebase是如何工作的,但直到最近,我通常只是做了一个git rebase -i HEAD~20,并修改了任何需要修改的内容。
我很惊讶地发现,这将修改所有20个提交的哈希值,即使我唯一采取的操作就是压缩最后两个。
我不知道是什么原因导致了其他18个提交的哈希改变,因为它们的父母和内容都没有改变。是吗也许是时间戳?
有没有办法防止这种情况发生呢?

col17t5w

col17t5w1#

关于rebase doc
之前保存到临时区域的提交会被重新应用到当前分支,一个接一个,按顺序。
当提交被“重新应用”时,它实际上是在创建一个全新的提交。..它的内容可能是相同的,但它将有一个不同的时间戳这是如何生成SHA的一部分。..因此,新的提交将具有新的SHA。
你可以阅读更多关于如何计算SHA的here

ppcbkaq5

ppcbkaq52#

你可能觉得你没有改变一些提交,但实际上你在几个方面改变了它们:

  • 每个提交都包含其父提交的sha1。因此,更改父节点的sha1会修改提交,因此也会修改它的sha1。哈希是连锁的,改变过去的任何事情都会改变未来。从技术上讲,这被称为Merkle tree。这是Git的一个重要属性,因为给定一个sha1,它不仅保证当前提交的完整性,而且保证导致它的整个历史的完整性(假设你在sha1中找不到冲突,which is no longer really the case today,但冲突仍然很难找到)。
  • 每个提交都包含项目当前状态的快照。因此,即使一个提交看起来是相同的,因为它引入了相同的diff,它也可能不对应于项目的相同状态(相同的树对象)。
  • 如前所述,提交包含时间戳(一个时间戳给作者,一个时间戳给评论者,第二个时间戳在你重新设置基础时被更改)。
yi0zb3m4

yi0zb3m43#

这将修改所有20个提交的哈希值,即使我采取的唯一行动是压缩最后两个。
如果你所说的“最后两次”指的是历史上最近的两次提交,那么不,它不会。
请具体一点,展示你看到的实际证据,你得到的待办事项清单和你执行的清单。特征化太不可靠了,很容易受到非共享上下文的影响。
例如,当我压缩最后两个提交时会发生什么,正如我所理解的那样:

$ git log --oneline --reverse @{u}..
00f53a2 echo >master6
afcef3e echo >master7
1f55c48 echo >master8
c3197a0 echo >master9
d30bb35 (HEAD -> master) echo >master10
$ GIT_SEQUENCE_EDITOR='sed -i 5s/pick/squash/' git rebase -i
[detached HEAD 16dc80d] echo >master9
 Date: Mon Feb 5 09:25:55 2018 -0800
 2 files changed, 2 insertions(+)
 create mode 100644 master10
 create mode 100644 master9
Successfully rebased and updated refs/heads/master.
$ git log --oneline --reverse @{u}..
00f53a2 echo >master6
afcef3e echo >master7
1f55c48 echo >master8
16dc80d (HEAD -> master) echo >master9
$

你可以看到最后两个提交被压缩在一起,所有历史没有改变的提交的id都保持不变。

kxe2p93d

kxe2p93d4#

请注意,在Git 2之前。29(2020年第4季度),Git还可以改变你在todo消息中重新建立基础的提交的哈希值,提交的哈希值应该 * 不 * 改变(因为你在重新播放旧提交到这个提交上)。
参见commit 5da69c0(2020年8月13日)。
(由Junio C Hamano -- gitster --合并至commit 4499a42,2020年8月19日)

rebase -i:修复todo中可能的哈希错误

创始人:Jussi Keränen
签字人:安蒂·凯兰宁
作者:Alban Gruun
todo_list_write_to_file”可以覆盖源自“find_unique_abbrev”的静态缓冲器,该静态缓冲器用于在todo编辑器中存储“# Rebase a..b onto c”消息的短提交散列“c”。
这是因为从' find_unique_abbrev '返回的缓冲区在对find_unique_abbrev进行4次以上调用之前是有效的。
由于' todo_list_write_to_file '为每个基于rebase的提交调用' find_unique_abbrev ',因此如果在rebase中有4个或更多提交,则' c '的散列将被覆盖。
这种行为自引入以来就被打破了。
通过在调用' todo_list_write_to_file '之前将short oncommit散列存储在保持有效的不同缓冲区中来修复。

6gpjuf90

6gpjuf905#

这是因为当你在HEAD中以交互方式重新建立节点的基础时,你是从HEAD中20个提交前的节点开始,然后重新应用后续的20个提交,就像它们是新的一样,并可以选择进行更改。即使你只改变了(压缩)提交-20和-19,你仍然会重新应用随后的18次提交,就好像它们是新的提交一样。对于这18个提交,你并没有重复使用同一个节点,你只是复制了它们的内容,但在你的重定基HEAD中添加了新的内容。
来自git rebase的书:
请再次记住,这是一个变基命令-每个提交都包含在HEAD~3范围内。.HEAD将被重写,无论您是否更改消息。

lymnna71

lymnna716#

如果你只是在本地变基,这不会改变哈希代码。这会发生在你推送代码的时候,只需要使用“git pull”,使用ff模式或ort模式,然后同时为提交拉取旧的哈希代码。为了防止这种情况,使用'git pull --rebase',不要合并远程提交。

相关问题