从技术上讲,您不能修改任何提交。甚至git commit --amend
不这样做。请记住,每个提交都由其哈希 ID 唯一标识。
您可以做的是获取一些现有的提交,提取它,并使用它来构建一个新的、不同的提交,该提交几乎与原始提交相同,但无论您认为有什么缺陷,都已修复。然后,你必须说服所有人——你自己,以及任何克隆了提交的人——停止使用旧的、有缺陷的提交,而改用闪亮的新提交。新的提交有一个新的、不同的哈希 ID。
如果闪亮的新提交不在分支的顶端——如果它向后退了两步,例如在这种情况下——那么你还有一个额外的问题。请记住,分支名称喜欢master
并develop
标识一个特定的提交,Git 将其称为分支的提示提交。每个提交还包含其父(前一个)提交的哈希 ID,这就是 Git 如何从最新的提交中找到较早的提交:
...--D--E--F--G <-- master
\
H--I--J--K <-- develop
在这里,大写字母代表丑陋的散列 ID。该名称master
标识提交G
:的提示。master
该名称develop
标识提交K
,即develop
. 从 commit 开始G
,Git 可以向后工作到F
, then E
,依此类推。从K
,Git 可以向后工作到J
,并最终到E
等等。
如果 commit 有问题I
,你可以做的是让 Git 提取 commit I
,对 index-and-work-tree 对进行一些更改(就像你对任何其他提交所做的那样),然后进行新的提交——让我们称它为I'
表示它的替代品I
——其父级与I
' 父级相同:
...--D--E--F--G <-- master
\
H--I--J--K <-- develop
\
I' <-- temporary
完成之后,我们现在只需要将 Git 复制J
到一个闪亮的 new上J'
,它的父级是I'
并且其效果与's 效果I'
相同:J
I
...--D--E--F--G <-- master
\
H--I--J--K <-- develop
\
I'-J' <-- temporary
现在我们重复K
make的技巧K'
:
...--D--E--F--G <-- master
\
H--I--J--K <-- develop
\
I'-J'-K' <-- temporary
最后,我们告诉 Git:删除临时名称。使名称develop
标识闪亮的新提交K'
而不是 icky old K
。 这给了我们:
...--D--E--F--G <-- master
\
H--I--J--K [abandoned]
\
I'-J'-K' <-- develop
如果我们停止绘制废弃的分支,看起来好像我们以某种方式更改了三个提交。但我们没有:新的提交有新的、不同的哈希 ID。
...--D--E--F--G <-- master
\
H--I'-J'-K' <-- develop
这就是这样git rebase -i
做的。听起来工作量很大,在某些情况下确实如此,但通常会让您git rebase -i
轻松无痛。
请注意,如果您已经推送到develop
其他地方,您现在必须强制-push 这个新开发,告诉另一个接收到提交的 Git I
,J
并且K
它应该忘记那些提交(以及任何以后的提交!),而是使用闪亮的新替代品。
如果其他用户选择了原始I-J-K
序列,您必须说服他们也放弃他们的 I-J-K
副本。如果他们在上面建立了自己的提交K
,你必须让他们在你闪亮的新的上面复制他们的旧提交K'
。对于所有其他用户来说,这可能是相当大的工作量,因此请确保您真的想对他们这样做。