git rebase -i -- 为什么要更改提交哈希值?
git rebase -i -- why is it changing commit hashes?
所以我或多或少熟悉 rebase 的工作原理,但直到最近我通常只是做一个 git rebase -i HEAD~20
,然后修改任何需要修改的东西。
得知这将修改所有 20 次提交的哈希,我感到很惊讶,即使我采取的唯一操作是压缩最后两次。
不过,我不确定是什么原因导致其他 18 次提交的哈希值发生变化,因为它们的父项和内容都没有发生变化……或者是这样吗?也许是时间戳?
还有什么办法可以避免吗?
来自rebase doc:
The commits that were previously saved into the temporary area are
then reapplied to the current branch, one by one, in order.
当提交是 "reapplied" 时,它实际上是在创建一个全新的提交...它的内容可能是相同的,但是 它会有不同的时间戳 这是它的 SHA 生成方式的一部分...因此新提交将具有新的 SHA。
您可以详细了解 SHA 的计算方式 here。
这是因为当您以交互方式将 HEAD 中的节点变基时,该节点比当前提交早 20 次提交,您是从 HEAD 中 20 次提交之前的节点开始,并重新应用后续 20 次提交,就好像它们是新的一样,进行更改的选项。即使您只更改(压缩)提交 -20 和 -19,您仍然会重新应用后续的 18 次提交,就好像它们是新提交一样。您没有为这 18 次提交重新使用相同的节点,您正在复制它们的内容,但将新的内容附加到重新设置基础的 HEAD。
来自 git 关于变基的书:
Remember again that this is a rebasing command – every commit included
in the range HEAD~3..HEAD will be rewritten, whether you change the
message or not.
您可能觉得您没有更改某些提交,但实际上您以多种方式更改了它们:
每个提交都包含其父项的 sha1。因此,更改父项的 sha1 会修改提交,因此会修改其 sha1。哈希是链式的,改变过去的任何事情都会改变未来。从技术上讲,这称为 Merkle tree. This is an important property of Git, because given a sha1 it guarantees not only the integrity of the current commit but also of the whole history leading to it (assuming you can't find a collision in sha1, which is no longer really the case today,但仍然很难找到碰撞)。
每个提交都包含项目当前状态的快照。因此,即使提交看起来相同,因为它引入了相同的差异,它也可能不对应于项目的相同状态(相同的树对象)。
如前所述,提交包含时间戳(作者一个时间戳,提交者一个时间戳,第二个在变基时更改)。
this will modify the hashes of all 20 commits, even if the only action I take is to squash the last two.
如果 "the last two" 你指的是历史上最近的两次提交,那么不,它不会。
请具体一点,出示您正在查看的实际证据、您获得的待办事项列表以及您执行的事项。特征太不可靠容易受到非共享上下文的影响。
例如,据我了解,当我压缩最后两次提交时会发生什么:
$ 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 保持不变。
请注意,在 Git 2.29(2020 年第 4 季度)之前,Git 还可以更改您在 todo
消息中重新定位的提交的哈希值,提交应该 不改变(因为你正在重播旧的提交到这个)。
参见 commit 5da69c0 (13 Aug 2020) by Antti Keränen (Detegr
)。
(由 Junio C Hamano -- gitster
-- in commit 4499a42 合并,2020 年 8 月 19 日)
rebase -i
: fix possibly wrong onto hash in todo
Found-by: Jussi Keränen
Signed-off-by: Antti Keränen
Acked-by: Alban Gruin
'todo_list_write_to_file
' may overwrite the static buffer, originating from 'find_unique_abbrev
', that was used to store the short commit hash 'c
' for "# Rebase a..b onto c
" message in the todo editor.
This is because the buffer that is returned from 'find_unique_abbrev
' is valid until 4 more calls to find_unique_abbrev
are made.
As 'todo_list_write_to_file
' calls 'find_unique_abbrev
' for each rebased commit, the hash for 'c
' is overwritten if there are 4 or more commits in the rebase.
This behavior has been broken since its introduction.
Fix by storing the short onto commit hash in a different buffer that remains valid, before calling 'todo_list_write_to_file
'.
所以我或多或少熟悉 rebase 的工作原理,但直到最近我通常只是做一个 git rebase -i HEAD~20
,然后修改任何需要修改的东西。
得知这将修改所有 20 次提交的哈希,我感到很惊讶,即使我采取的唯一操作是压缩最后两次。
不过,我不确定是什么原因导致其他 18 次提交的哈希值发生变化,因为它们的父项和内容都没有发生变化……或者是这样吗?也许是时间戳?
还有什么办法可以避免吗?
来自rebase doc:
The commits that were previously saved into the temporary area are then reapplied to the current branch, one by one, in order.
当提交是 "reapplied" 时,它实际上是在创建一个全新的提交...它的内容可能是相同的,但是 它会有不同的时间戳 这是它的 SHA 生成方式的一部分...因此新提交将具有新的 SHA。
您可以详细了解 SHA 的计算方式 here。
这是因为当您以交互方式将 HEAD 中的节点变基时,该节点比当前提交早 20 次提交,您是从 HEAD 中 20 次提交之前的节点开始,并重新应用后续 20 次提交,就好像它们是新的一样,进行更改的选项。即使您只更改(压缩)提交 -20 和 -19,您仍然会重新应用后续的 18 次提交,就好像它们是新提交一样。您没有为这 18 次提交重新使用相同的节点,您正在复制它们的内容,但将新的内容附加到重新设置基础的 HEAD。
来自 git 关于变基的书:
Remember again that this is a rebasing command – every commit included in the range HEAD~3..HEAD will be rewritten, whether you change the message or not.
您可能觉得您没有更改某些提交,但实际上您以多种方式更改了它们:
每个提交都包含其父项的 sha1。因此,更改父项的 sha1 会修改提交,因此会修改其 sha1。哈希是链式的,改变过去的任何事情都会改变未来。从技术上讲,这称为 Merkle tree. This is an important property of Git, because given a sha1 it guarantees not only the integrity of the current commit but also of the whole history leading to it (assuming you can't find a collision in sha1, which is no longer really the case today,但仍然很难找到碰撞)。
每个提交都包含项目当前状态的快照。因此,即使提交看起来相同,因为它引入了相同的差异,它也可能不对应于项目的相同状态(相同的树对象)。
如前所述,提交包含时间戳(作者一个时间戳,提交者一个时间戳,第二个在变基时更改)。
this will modify the hashes of all 20 commits, even if the only action I take is to squash the last two.
如果 "the last two" 你指的是历史上最近的两次提交,那么不,它不会。
请具体一点,出示您正在查看的实际证据、您获得的待办事项列表以及您执行的事项。特征太不可靠容易受到非共享上下文的影响。
例如,据我了解,当我压缩最后两次提交时会发生什么:
$ 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 保持不变。
请注意,在 Git 2.29(2020 年第 4 季度)之前,Git 还可以更改您在 todo
消息中重新定位的提交的哈希值,提交应该 不改变(因为你正在重播旧的提交到这个)。
参见 commit 5da69c0 (13 Aug 2020) by Antti Keränen (Detegr
)。
(由 Junio C Hamano -- gitster
-- in commit 4499a42 合并,2020 年 8 月 19 日)
rebase -i
: fix possibly wrong onto hash in todoFound-by: Jussi Keränen
Signed-off-by: Antti Keränen
Acked-by: Alban Gruin
'
todo_list_write_to_file
' may overwrite the static buffer, originating from 'find_unique_abbrev
', that was used to store the short commit hash 'c
' for "# Rebase a..b onto c
" message in the todo editor.This is because the buffer that is returned from '
find_unique_abbrev
' is valid until 4 more calls tofind_unique_abbrev
are made.As '
todo_list_write_to_file
' calls 'find_unique_abbrev
' for each rebased commit, the hash for 'c
' is overwritten if there are 4 or more commits in the rebase.
This behavior has been broken since its introduction.Fix by storing the short onto commit hash in a different buffer that remains valid, before calling '
todo_list_write_to_file
'.