Git非快进被拒绝


88

我觉得这个问题已经被问过很多次了,但是解决方案通常是“我删除了目录,并重新进行了结帐。” 我进行了提交和推送,但是意识到我在提交消息中引用了错误的凭单号码。因此,我在SO上寻求一种快速解决方案,并最终在终端中输入了以下内容:

$ git reset --soft HEAD^
$ git commit -m "... correct message ..."

唯一的问题是我收到以下错误消息:

To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes before pushing again.  See the 'Note about
fast-forwards' section of 'git push --help' for details.

我正在使用git-flow模型,并且正在开发分支。我怎样才能重新合并东西使git再次开心呢?


Answers:



174

如果按一个提交到服务器,然后重写在本地提交(有git resetgit rebasegit filter-branch,或其他任何历史操作),然后推说改写提交备份到服务器上,你会搞砸了谁比谁已经退出。这是一个例子。说您已提交A,并将其推送到服务器。

-*-*-A <-主

-*-*-A <-起源/母版

现在,您决定以您提到的方式重写A,然后重新设置并重新提交。请注意,这留下了一个悬空的提交A,由于无法到达,最终将对其进行垃圾回收。

-*-*-一个
    \
     A'<-大师

-*-*-A <-起源/母版

假设弗雷德master在执行此操作时从服务器中拉出其他人,他们将获得对A的引用,他们可能从以下地方开始工作:

-*-*-A'<-主

-*-*-A <-起源/母版

-*-*-AB <-弗雷德/大师

现在,如果您能够将A'推送到原点/主节点,这将创建非快进,则其历史记录中就不会包含A。因此,如果弗雷德试图再次拉,他将突然不得不合并,并重新引入A提交:

-*-*-A'<-主

-*-*-A <-起源/母版

-*-*-AB- \ 
    \ * <-弗雷德/大师
     一个' - /

如果Fred恰好注意到这一点,那么他可以进行重新设置基准,这将阻止提交A再次出现。但是他必须注意到这一点,并记住要这样做。如果您有多个人将A拉倒,则他们都必须重新设置基准,以避免在树中获得额外的A提交。

因此,通常不要在其他人提供的回购中更改历史记录。但是,如果您碰巧知道没有其他人正在从该存储库中提取信息(例如,这是您自己的私人存储库,或者只有一个其他开发人员可以轻松地与该项目进行协作),那么您可以强制执行通过运行更新:

git push -f

要么

git push origin +master

这些都将忽略对非快进推送的检查,并将服务器上的内容更新为新的A'版本,放弃A版本,以便最终对其进行垃圾回收。

receive.denyNonFastForwardsconfig选项可能会完全禁用强制推送。默认情况下,此选项在共享存储库上启用。在这种情况下,如果您确实要强制执行推送,则最好的选择是使用删除分支并重新创建分支git push origin :master; git push origin master:master。但是,由于denyNonFastForwards上述原因而启用了该选项。在共享存储库上,这意味着现在使用它的每个人都需要确保他们基于新的历史记录。

在共享存储库上,通常最好将新的提交放在最上面,以解决您遇到的任何问题;您可以git revert用来生成将撤消先前提交的更改的提交。


很好的教育,最后您正确地获得了命令,但是我的分支称为develop(基于git-flow),另一个人+develop输入了他的命令-支票交给了他。无论如何,您都获得了天文数字:P
rynmrtn 2011年

7
或者使用较少的神秘git push --force
贝内特麦克尔威

3
@Panique您正在尝试允许多个人同时在一个大型,复杂的代码库上工作,而又不会互相阻塞(一次只能允许一个人进行操作),并且彼此之间不会被更改覆盖。您需要每个人都能够独立进行更改,并合并这些更改。合并(无论是手动还是自动)都可能导致意外的问题;因此,您希望保留尽可能多的信息,以便能够弄清楚如果出错了会发生什么。这本质上很复杂。它不脏,只是一个难题。
Brian Campbell

我同时尝试了-f和+选项来重写远程回购历史记录。在这两种选择中,我都遇到了非快进问题。[5:05 PM] $ git push -f origin local_A:remote_A正在计数对象:35,已完成。增量压缩最多使用2个线程。压缩对象:100%(18/18),已完成。书写对象:100%(21/21),7.41 KiB,完成。总计21(增量9),重用0(增量0)远程:为了防止丢失历史记录,拒绝了非快进更新。合并远程更改(例如“ git pull”),然后再次推送。有关详细信息,请参见“ git push --help”的“关于快进的说明”部分。
Srikanth

4
@Srikanth可以使用receive.denyNonFastForwardsconfig选项完全禁用强制推送。默认情况下,此选项在共享存储库上启用。在这种情况下,如果您确实要强制执行推送,则最好的选择是使用删除分支并重新创建分支git push origin :remote_A; git push origin local_A:remote_A。但是,请阅读我上面写的关于在共享存储库上进行这种工作流的想法不好的主意。只有在某些原因导致要删除或重写的提交中出现严重问题时,才应尝试这样做。
布莱恩·坎贝尔2013年

14

您可能需要执行git pull,它可以为您自动合并内容。然后,您可以再次提交。如果您有冲突,它将提示您解决冲突。

请记住,如果您尚未更新gitconfig来指定...,则必须指定要从哪个分支中提取...

例如:

git pull origin develop:develop

仍然为非快进而生气。关于如何迫使其合并的任何想法?! [rejected] develop -> develop (non-fast-forward)
rynmrtn 2011年

我认为该开关是-f,但我可能错了。 kernel.org/pub/software/scm/git/docs/git-pull.html
Tony,

这部分起作用。我没有在github上看到更新,(它甚至将先前的提交显示为最新提交git push origin develop
rynmrtn 2011年

7

我使用EGit时也遇到了这个问题。刚尝试到rebase当前分支,它就起作用了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.