为何GitHub无报错而自建远程Git服务器报“分支已检出”错误?
Git远程推送差异问题:GitHub vs 普通远程服务器
问题场景
使用GitHub的操作流程
- 本地机器执行:
git init testrepo - 在GitHub网页界面创建名为
test.git的仓库 - 本地依次执行以下命令:
cd testrepo git remote add origin https://github.com/Someuser/test.git touch somefile git add . git commit -m 'first' git push -u origin master
操作一切正常,somefile成功同步到GitHub仓库。
使用普通远程服务器的操作流程
- 本地机器执行:
git init testrepo - 远程机器执行:
git init test.git - 本地依次执行以下命令:
cd testrepo git remote add origin remotemachine:~/test.git touch somefile git add . git commit -m 'first' git push -u origin master
执行后出现错误:
! [remote rejected] master -> master (branch is currently checked out)
疑问
操作流程看起来一致,为什么GitHub能正常接收推送,普通远程服务器却拒绝?该怎么解决这个问题?
问题原因与解决方法
原因分析
GitHub网页创建的仓库默认是裸仓库(Bare Repository)——这种仓库没有工作区,只存储Git版本控制的核心元数据(相当于本地仓库里的.git目录内容),设计目的就是专门用来接收远程推送。
而你在远程服务器用git init test.git创建的是非裸仓库,它包含完整的工作区和.git目录,此时远程仓库的master分支处于已检出状态。Git禁止直接推送到非裸仓库的当前检出分支,因为推送会直接修改仓库的分支指针,但远程的工作区文件不会自动同步更新,会导致工作区内容和仓库记录不一致,引发各种混乱。
解决方法
方法1:将远程仓库改为裸仓库(推荐)
这是最标准的解决方案,因为共享的远程仓库本来就应该用裸仓库。操作步骤如下:
- 在远程机器上进入仓库目录:
cd ~/test.git - 如果需要保留远程工作区的文件,先备份:
mv ./* ../test-repo-backup/ - 将仓库切换为裸仓库模式:
git config --bool core.bare true - 删除原工作区的文件(裸仓库不需要工作区):
rm -rf ./*
或者更干脆:直接删掉原仓库,重新创建裸仓库
rm -rf ~/test.git git init ~/test.git --bare
方法2:临时切换远程仓库的检出分支(不推荐)
如果必须保留非裸仓库,可以先在远程切换到其他分支,再推送:
- 远程机器执行:
cd ~/test.git && git checkout -b temp - 本地执行推送:
git push -u origin master
但这种方法只是临时解决,后续如果远程切回master分支,再次推送还是会报错,而且非裸仓库并不适合作为团队共享的推送目标。
内容的提问来源于stack exchange,提问作者Andrew Anderson
相关产品推荐
相关产品推荐

