如果我推送修改后的提交,它会创建一个新的提交吗?

If I push an amended commit will it create a new commit?

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

If do git status 它表示两个分支分别有 1 和 1 个不同的提交。

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

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

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

要解决这个问题,您需要创建一个新分支来保留您的修改,检查初始分支,重置回修改前的状态,从远程拉下更改。然后合并到您的单独分支并向上推。

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到远程,大家都很高兴。

tl;博士

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

提交 ID 剖析

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

git cat-file -p HEAD

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

  • Parent
  • 作者
  • 提交者
  • 留言

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

修正就是改写历史

这就是为什么如果你修改一个提交——例如通过改变它的消息——它将有一个不同的ID之前。你实际上是 rewriting history.

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