如何将修改后的提交推送到远程Git存储库?

How do I push amended commit to the remote Git repository?

当我处理了一点源代码后,我做了我通常做的事情提交,然后推到一个远程存储库。但后来我注意到我忘记在源代码中组织导入。所以我执行修正命令来替换先前的提交:

1
> git commit --amend

不幸的是,无法将提交推回到存储库中。它是这样被拒绝的:

1
2
3
4
> git push origin
To //my.remote.repo.com/stuff.git/
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to '//my.remote.repo.com/stuff.git/'

我该怎么办?(我可以访问远程存储库。)


实际上,我曾经和--force.git仓库一起推过,被linus big time骂了一顿。一般来说,这会给其他人带来很多问题。一个简单的答案是"不要这样做"。

我看到其他人给出了这样做的配方,所以我不会在这里重复。但这里有一个技巧,可以在您用--force(或+master)推出修改后的commit之后,从这种情况中恢复过来。

  • 使用git reflog查找您修改的旧承诺(称为old,我们将调用您通过修改new创建的新承诺)。
  • oldnew之间创建合并,记录new的树,如git checkout new && git merge -s ours old
  • 把它和你的主人合并在一起。
  • git push . HEAD:master更新您的主文件。
  • 把结果推出来。
  • 那么不幸的是,那些将工作建立在你通过修改和强制推行而抹杀的承诺之上的人,将会看到合并的结果,你会看到你对new的支持超过了old的支持。他们后来的合并不会看到你的修改导致的oldnew之间的冲突,所以他们不必受苦。


    您看到的是Git安全功能。Git拒绝用您的分支更新远程分支,因为分支的head commit不是您要推送的分支的当前head commit的直接后代。

    如果不是这样的话,那么在同一时间推到同一个存储库的两个人就不会知道在同一时间有一个新的提交出现了,而最后推到最后一个的人就会在没有意识到这一点的情况下失去前一个推送者的工作。

    如果您知道您是唯一一个推送的人,并且您希望推送修改后的提交,或者推送一个结束分支的提交,那么您可以使用-f开关"强制"git更新远程分支。

    1
    git push -f origin master

    即使这样也可能不起作用,因为Git允许远程存储库通过使用配置变量receive.denynonfastforwards拒绝远端的非fastforward推送。如果是这种情况,拒绝原因如下(请注意"远程拒绝"部分):

    1
     ! [remote rejected] master -> master (non-fast forward)

    为了解决这个问题,您要么需要更改远程存储库的配置,要么作为一个肮脏的黑客,您可以删除并重新创建分支,这样:

    1
    2
    git push origin :master
    git push origin master

    通常,git push的最后一个参数使用格式:,其中local_ref是本地存储库上分支的名称,remote_ref是远程存储库上分支的名称。此命令对使用两个速记。:master有一个空的本地引用,这意味着将一个空分支推到远程端master上,即删除远程分支。没有:的分支名称意味着将具有给定名称的本地分支推送到具有相同名称的远程分支。在这种情况下,mastermaster:master的缩写。


    快速咆哮:没有人在这里发布简单的答案这一事实表明了git-cli所表现出的绝望的用户敌意。

    不管怎么说,如果你没有试图强行推,那么做的"明显"方法就是先拉。这就拉动了你修改过的变化(现在已经没有了),这样你就可以再次拥有它了。

    一旦解决了任何冲突,就可以再次推动。

    所以:

    1
    git pull

    如果在pull中得到错误,那么本地存储库配置中可能有错误(在.git/config分支部分中有一个错误的引用)。

    之后

    1
    git push

    也许你会对这个主题有一个额外的承诺,告诉你一个"微不足道的合并"。


    简短回答:不要推动修订后的承诺公开回购。

    长话短说:一些git命令,比如git commit --amendgit rebase,实际上重写了历史图。这很好,只要你还没有发布你的更改,但一旦你这样做了,你真的不应该把历史弄乱,因为如果有人已经得到了你的更改,那么当他们再次尝试拉时,它可能会失败。您不应该修改提交,而应该只对更改进行新的提交。

    但是,如果您真的,真的想推动修改后的提交,您可以这样做:

    1
    $ git push origin +master:master

    领先的+标志将迫使推动发生,即使它不会导致"快进"承诺。(当您推送的更改是已在公共repo中的更改的直接后代时,将发生快速向前提交。)


    下面是一个非常简单和干净的方法,可以在您已经创建了commit --amend之后推动您的更改:

    1
    2
    3
    4
    5
    6
    git reset --soft HEAD^
    git stash
    git push -f origin master
    git stash pop
    git commit -a
    git push origin master

    执行以下操作:

    • 将分支头重置为父提交。
    • 把最后的承诺藏起来。
    • 强制推到远程。远程现在没有最后一次提交。
    • 打开你的藏匿处。
    • 干净利落地承诺。
    • 按遥控器。

    如果将此应用于其他分支或远程,请记住更改"来源"和"主控"。


    我通过放弃本地修改的提交并在顶部添加新的更改来解决此问题:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # Rewind to commit before conflicting
    git reset --soft HEAD~1

    # Pull the remote version
    git pull

    # Add the new commit on top
    git add ...
    git commit
    git push


    我也有同样的问题。

    • 意外地修改了上一个已被推送的提交
    • 在本地做了很多更改,提交了大约五次
    • 尝试推送、出错、惊慌失措、合并远程文件、获取大量非我的文件、推送、失败等。

    作为一个Git新手,我认为这是完全的Fubar。

    解决方案:有点像@bara suggested+创建了一个本地备份分支

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # Rewind to commit just before the pushed-and-amended one.
    # Replace <hash> with the needed hash.
    # --soft means: leave all the changes there, so nothing is lost.
    git reset --soft <hash>

    # Create new branch, just for a backup, still having all changes in it.
    # The branch was feature/1234, new one - feature/1234-gone-bad
    git checkout -b feature/1234-gone-bad

    # Commit all the changes (all the mess) not to lose it & not to carry around
    git commit -a -m"feature/1234 backup"

    # Switch back to the original branch
    git checkout feature/1234

    # Pull the from remote (named 'origin'), thus 'repairing' our main problem
    git pull origin/feature/1234

    # Now you have a clean-and-non-diverged branch and a backup of the local changes.
    # Check the needed files from the backup branch
    git checkout feature/1234-gone-bad -- the/path/to/file.php

    也许这不是一个快速而干净的解决方案,我失去了我的历史记录(1次提交而不是5次),但它节省了一天的工作。


    如果你知道没有人取消了你的联合国修正承诺,那么使用git push--force-with-lease选项。

    在TortoisGit中,您可以在"push…"选项"force:may discard"和检查"known changes"下执行相同的操作。

    Force (May discard known changes) allows the remote repository to accept a safer non-fast-forward push. This can cause the remote repository to lose commits; use it with care. This can prevent from losing unknown changes from other people on the remote. It checks if the server branch points to the same commit as the remote-tracking branch (known changes). If yes, a force push will be performed. Otherwise it will be rejected. Since git does not have remote-tracking tags, tags cannot be overwritten using this option.


    如果您没有将代码推送到远程分支(github/bitback),您可以在命令行上更改commit消息,如下所示。

    1
     git commit --amend -m"Your new message"

    如果您在一个特定的分支上工作,请执行以下操作:

    1
    git commit --amend -m"BRANCH-NAME: new message"

    如果您已经用错误的消息推送了代码,那么在更改消息时需要小心。也就是说,在您更改提交消息并再次尝试推送之后,最终会出现问题。要使其平滑,请执行以下步骤。

    在做之前请先把整个答案读一遍

    1
    2
    3
    git commit --amend -m"BRANCH-NAME : your new message"

    git push -f origin BRANCH-NAME                # Not a best practice. Read below why?

    重要提示:当您直接使用force push时,您可能会遇到其他开发人员正在处理同一分支的代码问题。因此,为了避免这些冲突,您需要在强制执行之前从分支中提取代码:

    1
    2
    3
     git commit --amend -m"BRANCH-NAME : your new message"
     git pull origin BRANCH-NAME
     git push -f origin BRANCH-NAME

    这是更改提交消息(如果已经推送)时的最佳实践。


    您收到此错误是因为git远程已经有这些提交文件。您必须强制推动分支机构才能工作:

    1
    git push -f origin branch_name

    还要确保从远程提取代码,因为团队中的其他人可能已经将代码推到了同一个分支。

    1
    git pull origin branch_name

    这是我们必须强制将提交推送到远程的情况之一。


    下面是一个非常简单和干净的方法,可以在您已经创建了一个git add"your files"git commit --amend之后推动您的更改:

    1
    git push origin master -f

    或:

    1
    git push origin master --force


    我只是一直按照吉特告诉我的做。所以:

    • 无法推送,因为修改了提交。
    • 我按建议拉。
    • 合并失败。所以我手动修复它。
    • 创建新的提交(标记为"合并")并推动它。
    • 好像有用!

    注意:修改后的提交是最新的。


    我必须解决这个问题,从远程回购中退出,并处理产生的合并冲突,提交,然后推送。但我觉得有更好的方法。


    在这里,我如何修复以前提交中的编辑:

  • 把你的工作留到现在为止。
  • 现在就把你的更改藏起来,如果做了:git stash现在你的工作副本在你上次提交的状态下是干净的。
  • 进行编辑和修复。
  • 提交"修正"模式的变更:git commit --all --amend
  • 您的编辑器将上来请求日志消息(默认情况下,是旧的日志消息)。保存并在您满意时退出编辑器。

    新更改将添加到旧提交中。你自己去看看git loggit diff HEAD^

  • 重新应用您的隐藏更改(如果有):git stash apply