【问题标题】:If I push an amended commit will it create a new commit?如果我推送一个修改过的提交,它会创建一个新的提交吗?
【发布时间】:2016-04-01 08:43:53
【问题描述】:

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

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

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

【问题讨论】:

    标签: git push git-amend


    【解决方案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推送到远程而不冲突,每个人都很开心。

    【讨论】:

    • 谢谢,很好的解释。所以问题是我已经推送了那个提交。我想要做的是用 A' 替换 A,这样我的远程和本地分支都将指向 A'。我怎样才能做到这一点?附言我是唯一一个在这个项目上工作的人。
    • 如果你真的想替换它,尽管我的所有警告;),那么你可以使用git push --force 覆盖遥控器。或者将该修复推送为提交B
    【解决方案2】:

    tl;博士

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

    提交 ID 剖析

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

    git cat-file -p HEAD
    

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

    • 父母
    • 作者
    • 提交者
    • 留言

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

    修改就是改写历史

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

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

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

      • 听起来有点复杂,简单的pull就会自动合并。所以:git pull && git push。尽管如此,OP 并没有指定遥控器是公开的。如果不是,那么只需 git push -f 即可避免合并。
      • 是的,不是唯一可用的方法。但是最好知道,一旦你推送到任何远程,你就不应该真正在本地修改提交。
      • 有没有办法可以用新的提交替换我的旧提交?类似修改的东西,但在这种情况下,我认为修改不是一个好主意,因为我已经将我的提交推送到远程分支上。它是一个私人遥控器。
      猜你喜欢
      • 2020-12-18
      • 1970-01-01
      • 2020-03-11
      • 2021-05-05
      • 2017-12-21
      • 2019-09-21
      • 1970-01-01
      • 2017-12-22
      • 2019-12-31
      相关资源
      最近更新 更多