我已经在远程分支上推送了一个提交,现在我想更改它的内容,所以我尝试了git amend
.
如果这样做git status
,则表示两个分支分别有 1 个和 1 个不同的提交。
现在,如果我使用相同的提交消息推送修改后的提交,那会添加一个新的提交还是会更改我推送的最后一个提交?
git commit --amend
,就像git rebase
,将创建一个新的提交对象。该对象基于先前存在的提交,但它仍然是一个新提交并完全替换旧提交。
回顾历史,可能是这样的:
master
↓
* --- * --- * --- A
考虑到这A
是原始提交。如果我们现在修改这个提交,那么我们会得到以下结果:
* --- * --- * --- A
\
--- A'
↑
master
所以我们得到了一个不同的提交对象A'
,具有不同的哈希,我们所在的分支(这里:master)被更新为指向这个。
现在,如果我们向该视图添加一个远程存储库,并且我们A
之前推送到远程,那么它看起来像这样:
origin/master
↓
* --- * --- * --- A
\
--- A'
↑
master
所以远程仍然指向原始提交A
,但我们的本地分支指向修改后的A'
。这是一个问题,因为我们无法推送A'
和origin/master
指出,因为这会从历史记录A'
中删除已经推送的提交。A
我们可以使用强制推git push --force
送来强制 Git 更新远程分支并确实A
从历史记录中删除。重要的是要注意,这将打破每个已经A
从遥控器获取的历史记录。如果其他一些开发人员A
现在有远程点A'
,那么他们就有了必须手动修复的冲突。这通常很痛苦,因此您应该始终遵循一条规则:
永远不要变基(或修改)以前发布的提交。
更好的选择是添加一个新的提交B
,它只是对以下内容进行修复A
:
origin/master
↓
* --- * --- * --- A --- B
↑
master
这样,已经发布的历史仍然兼容新的历史,所以我们可以推B
送到远程而不冲突,每个人都很高兴。
推送修改后的提交意味着推送不同的提交。
提交的唯一 ID 由其元数据的 SHA-1 哈希组成。哪个元数据?找出方法之一是使用cat-file
管道命令:
git cat-file -p HEAD
运行此命令后,您将看到一个包含以下字段的列表:
如果这些字段中的任何一个发生变化,它们的 SHA-1 哈希值也会发生变化,从而授予提交一个全新的 ID。
这就是为什么如果你修改一个提交——例如通过改变它的消息——它将有一个与以前不同的 ID 。你有效地改写了历史。
请注意,提交的父项的 ID也包含在元数据中。这意味着一旦提交更改了 ID,它的所有后代也会像多米诺骨牌效应一样更改 ID。
一旦你推送到远程,你不应该在本地修改任何现有的提交。
您实际上已经在本地创建了一个新的提交(有一个新的提交 ID)并替换了旧的提交,但旧的提交仍然存在于远程。这会导致您看到 1 前和 1 后消息。
要解决此问题,您需要创建一个新分支以保留您的修改,检出初始分支,重置回您进行修改之前,从远程下拉更改。然后合并到您单独的分支中并向上推。