8

我已经在远程分支上推送了一个提交,现在我想更改它的内容,所以我尝试了git amend.

如果这样做git status,则表示两个分支分别有 1 个和 1 个不同的提交。

现在,如果我使用相同的提交消息推送修改后的提交,那会添加一个新的提交还是会更改我推送的最后一个提交?

4

3 回答 3

15

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送到远程而不冲突,每个人都很高兴。

于 2016-04-01T08:54:37.440 回答
2

tl;博士

推送修改后的提交意味着推送不同的提交。

提交 ID 剖析

提交的唯一 ID 由其元数据的 SHA-1 哈希组成。哪个元数据?找出方法之一是使用cat-file 管道命令

git cat-file -p HEAD

运行此命令后,您将看到一个包含以下字段的列表:

  • 家长
  • 作者
  • 提交者
  • 信息

如果这些字段中的任何一个发生变化,它们的 SHA-1 哈希值也会发生变化,从而授予提交一个全新的 ID

修改就是改写历史

这就是为什么如果你修改一个提交——例如通过改变它的消息——它将有一个与以前不同的 ID 。你有效地改写了历史

请注意,提交的项的 ID也包含在元数据中。这意味着一旦提交更改了 ID,它的所有后代也会像多米诺骨牌效应一样更改 ID。

于 2016-04-01T09:11:03.733 回答
1

一旦你推送到远程,你不应该在本地修改任何现有的提交。

您实际上已经在本地创建了一个新的提交(有一个新的提交 ID)并替换了旧的提交,但旧的提交仍然存在于远程。这会导致您看到 1 前和 1 后消息。

要解决此问题,您需要创建一个新分支以保留您的修改,检出初始分支,重置回您进行修改之前,从远程下拉更改。然后合并到您单独的分支中并向上推。

于 2016-04-01T08:53:49.757 回答