Git推送错误:拒绝更新签出的分支

Git推送错误:拒绝更新签出的分支,git,git-push,Git,Git Push,我已解决了一些合并冲突,提交了,然后尝试推送我的更改,并收到以下错误: c:\Program Files (x86)\Git\bin\git.exe push --recurse-submodules=check "origin" master:master Done remote: error: refusing to update checked out branch: refs/heads/master remote: error: By default, updating the cur

我已解决了一些合并冲突,提交了,然后尝试推送我的更改,并收到以下错误:

c:\Program Files (x86)\Git\bin\git.exe push --recurse-submodules=check "origin" master:master
Done
remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error: 
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error: 
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.
To C:/Development/GIT_Repo/Project
 ! [remote rejected] master -> master (branch is currently checked out)
error: failed to push some refs to 'C:/Development/GIT_Repo/Project'

有人知道是什么导致了这个错误吗?

原因:您正在推送到一个非裸存储库

有两种类型的存储库:

裸存储库没有工作副本,您可以推送到它们。这些就是您在Github中获得的存储库类型!如果要创建裸存储库,可以使用

git init --bare
因此,简而言之,您不能推送到非裸存储库(编辑:您不能推送到存储库当前签出的分支。对于裸存储库,您可以推送到任何分支,因为没有签出。尽管可能,推送到非裸存储库并不常见)。您可以做的是从另一个存储库获取和合并。这就是您在Github中看到的
拉取请求的工作方式。你让他们从你身边拉,而不是强迫他们


更新:感谢VonC在最新git版本(目前为2.3.0)中指出这一点。尽管如此,您仍然无法推送到脏的工作树,这无论如何都不是一个安全的操作。

Summary 您不能推送到存储库的一个签出分支,因为它会给该存储库的用户带来麻烦,很可能导致数据和历史的丢失。但您可以推送到同一存储库的任何其他分支

由于裸存储库从未签出任何分支,因此始终可以推送到裸存储库的任何分支

问题的解剖 签出分支后,提交将添加一个新的提交,当前分支的头作为其父级,并将分支的头移动为该新提交

所以

变成

A ← B ← C
        ↑
    [HEAD,branch1]
但是,如果有人可以将其推到中间的分支,用户将进入git称之为“分离头”的模式:

A ← B ← X
    ↑   ↑
[HEAD] [branch1]
现在用户不再在branch1中,没有明确要求签出另一个分支。更糟糕的是,用户现在在任何分支之外,任何新的提交都将挂起

      [HEAD]
        ↓
        C
      ↙
A ← B ← X
        ↑
       [branch1]

假设在这一点上,如果用户签出另一个分支,那么这个悬而未决的提交对于Git的垃圾收集器来说是公平的游戏

可能您的远程repo位于您想要推送的分支中。您可以尝试签出远程计算机中的另一个分支。我这样做了,然后这些错误消失了,我把成功推到了远程回购上。请注意,我使用ssh来连接自己的服务器,而不是github.com。

我解决了这个问题,首先验证了远程服务器没有签出任何东西(实际上不应该签出),然后使用以下方法将其裸露:

$ git config --bool core.bare true
在那之后,git推送工作正常。

TLDR
  • 再次推拉:
    git-Pull&&git-push
  • 还是个问题吗?推入不同的分支:
    git推入原始主机:foo
    ,并将其合并到远程repo上
  • 或者,通过添加
    -f
    (需要忽略
    denyCurrentBranch
    )强制推送

  • 基本上,该错误意味着您的存储库没有更新远程代码(其索引和工作树与您推送的不一致)

    通常,您应该先
    以获取最近的更改,然后再

    如果没有帮助,请尝试插入其他分支,例如:

    git push origin master:foo
    
    然后将远程存储库上的该分支与master合并

    如果您通过
    git-rebase
    故意更改了一些过去的提交,并且希望用更改覆盖回购,则可能需要通过添加
    -f
    /
    --force
    参数来强制推送(如果您没有执行
    rebase
    ),则不建议这样做)。如果仍然无法工作,您需要通过以下方式将远程上的
    receive.denyCurrentBranch
    设置为
    ignore
    ,如git消息所示:

    git config receive.denyCurrentBranch ignore
    

    因为已有一个存储库正在运行

    git config --bool core.bare true
    
    在远程存储库上,就足够了

    来自core.bare文档

    如果为true(bare=true),则假定存储库为空,没有关联的工作目录。如果是这种情况,许多需要工作目录的命令将被禁用,例如git add或git merge(但您可以推送到它)


    在创建存储库时,git clone或git init会自动猜测此设置。默认情况下,以“/.git”结尾的存储库被假定为非裸存储库(bare=false),而所有其他存储库被假定为裸存储库(bare=true)。

    将cd放入远程计算机上要推入的repo/目录中,然后输入

    $ git config core.bare true
    

    对我来说,以下方法奏效了:

    git config --global receive.denyCurrentBranch updateInstead
    
    我使用Git将驱动器F:(几乎全部)设置为在我的Windows 10台式机和我的Windows 10笔记本电脑之间同步。最后,我在两台机器上都运行了上述命令

    首先,我在网络上共享了桌面的F驱动器。然后,我可以通过运行以下命令在笔记本电脑上克隆它:

    F:
    git clone 'file://///DESKTOP-PC/f'
    
    不幸的是,在我的笔记本电脑上,所有的文件都被放在“F:\F”下,而不是直接放在F:\F下。但我可以手动剪切和粘贴它们。Git后来仍然在新地点工作

    然后,我尝试对笔记本电脑上的文件进行一些更改,提交这些文件,并将它们推回到桌面。直到我运行上面提到的gitconfig命令,这才起作用

    请注意,我在两台计算机上都从Windows PowerShell中运行了所有这些命令

    更新:在某些情况下,我在推动变革方面仍然存在问题。我终于开始拉取更改,在我想要拉取最新提交的计算机上运行以下命令:


    我之所以会有这个错误,是因为git回购(意外)在同一地点被初始化了两次:第一次是作为非裸回购,第二次是作为裸回购。由于.git文件夹仍然存在,git假定
    F:
    git clone 'file://///DESKTOP-PC/f'
    
    git pull --all --prune