当我使用了一点源代码后,我做了我通常的事情提交,然后推送到远程存储库。但后来我注意到我忘记在源代码中组织导入。因此,我执行modify命令以替换先前的commit:

> git commit --amend

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

> 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/'

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


当前回答

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

如果不是这样的话,那么两个同时推到同一个存储库的人就不会知道同时有一个新的提交,而最后推的人都会失去前一个推的人的工作,而他们中的任何一个都没有意识到这一点。

如果你知道你是唯一一个推送的人,并且你想推送一个修改后的提交或推送一条返回分支的提交,你可以使用-f开关“强制”Git更新远程分支。

git push -f origin master

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

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

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

git push origin :master
git push origin master

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

其他回答

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

如果不是这样的话,那么两个同时推到同一个存储库的人就不会知道同时有一个新的提交,而最后推的人都会失去前一个推的人的工作,而他们中的任何一个都没有意识到这一点。

如果你知道你是唯一一个推送的人,并且你想推送一个修改后的提交或推送一条返回分支的提交,你可以使用-f开关“强制”Git更新远程分支。

git push -f origin master

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

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

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

git push origin :master
git push origin master

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

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

保存您的工作到目前为止。如果做了更改,现在就暂时保存:git Stash现在您的工作副本在上次提交时是干净的。进行编辑和修复。在“修改”模式下提交更改:gitcommit--all--modify您的编辑器将显示一条日志消息(默认情况下,是旧的日志消息)。保存并在满意时退出编辑器。新的更改将添加到旧的提交中。使用git log和git diff HEAD自行查看^重新应用隐藏的更改(如果有):git stash apply

如果您使用的是Visual Studio代码,可以尝试此扩展以使其更容易。

https://marketplace.visualstudio.com/items?itemName=cimdalli.git-提交修改推力

正如您从其名称中可以理解的,它连续执行命令

gitcommit—修改git push—力

简言之:不要将修改后的承诺推至公开回购。

长篇大论:一些Git命令,比如gitcommit--modify和gitrebase,实际上重写了历史图。只要你还没有发布你的更改,这是很好的,但一旦你发布了,你就真的不应该玩弄历史,因为如果有人已经得到了你的更改的话,那么当他们再次尝试时,可能会失败。您不应该修改提交,而应该使用更改进行新的提交。

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

$ git push origin +master:master

前导+符号将迫使推送发生,即使它不会导致“快进”提交。(当您推送的更改是公共回购中已存在更改的直接后代时,会发生快速提交。)

事实上,我曾经用武力和.git存储库推过一次,结果被Linus BIG TIME骂了一顿。一般来说,这会给其他人带来很多问题。一个简单的答案是“不要这样做”。

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

使用gitreflog查找您修改的旧提交(称之为旧提交,我们将调用您通过修改新提交创建的新提交)。在新旧之间创建一个合并,记录新的树,比如git checkout new&&git merge-s our old。使用gitmergemaster将其合并到您的master用git push更新你的主人。头部:主将结果推出来。

然后,那些不幸地将他们的工作建立在你通过修改和强制推动而消除的承诺之上的人将看到由此产生的合并,他们将看到你喜欢新的而不是旧的。他们后来的合并将不会看到由于您的修改而导致的新旧冲突,因此他们不必遭受损失。