git daemon 是零配置、秒启动的最轻量私有仓库方案,仅适用于局域网只读场景;ssh 方案最稳,适合需写权限的生产环境;git-http-backend 易出错且性能差,推荐直接用 gitea 等成熟服务。

用 git daemon 搭建最轻量的私有仓库服务
它不带认证、不走 HTTPS,但胜在零配置、秒启动,适合局域网内快速共享代码。如果你只是想让团队成员 git clone 一个只读仓库,或者 CI 机器拉取代码,git daemon 是最快路径。
常见错误现象:git clone git://localhost/myrepo 失败,提示 fatal: unable to connect to ... —— 很可能没开 daemon,或仓库没加 --export-all 标志。
- 确保仓库目录下存在
git-daemon-export-ok空文件,或启动时加--export-all - 运行命令:
git daemon --base-path=/path/to/repos --export-all --reuseaddr --verbose -
--base-path是父目录,不是单个仓库路径;/path/to/repos/myproject.git克隆时写git://host/myproject.git - Windows 下需用 Git for Windows 的 Bash 启动,CMD 直接跑会静默退出
用 ssh + 普通用户实现带权限的私有仓库
这是生产环境最稳的方案:复用系统用户、SSH 密钥认证、天然加密、无需额外服务进程。所有操作都在 shell 层完成,没有中间件拖慢或出错。
使用场景:小团队协作、CI/CD 接入、需要写权限(push)的私有仓库。
- 服务端只需一个 Linux 用户(如
git),家目录下建~/repos/myproject.git - 初始化仓库:
git init --bare ~/repos/myproject.git - 客户端克隆:
git clone git@server:/home/git/repos/myproject.git - 别用 root 用户跑 git;避免把仓库放在
/var/www这类被 Web 服务默认可读的路径,防止意外泄露
为什么不该用 httpd + git-http-backend 自建 CGI 服务
它理论上支持 HTTPS 和 Basic Auth,但实际部署中极易卡在 CGI 配置、PATH 环境变量、Git 版本兼容性上。Apache/Nginx 的 rewrite 规则一错,git push 就报 403 Forbidden 或 500 Internal Server Error,且错误日志极难定位。
性能影响:每次 push/fetch 都要 fork 一个新 git-http-backend 进程,高并发下响应延迟明显;Git 2.30+ 对 CGI 的 PATH 处理更严格,旧教程里的 ScriptAlias 配置大概率失效。
- 如果非要用 HTTP(S),直接上
gitea或gitlab-ce,它们内置了健壮的 Git HTTP 服务 - 自己配
git-http-backend前,先确认git --exec-path输出的路径已加入 Apache 的PassEnv PATH -
SetEnv GIT_PROJECT_ROOT /path/to/repos必须指向裸仓库父目录,且目录权限要让 web 用户可读(但不能可写)
权限隔离和钩子脚本的实际约束
Git 本身不提供细粒度权限控制(比如某分支只读、某目录不可改)。所谓“权限”,其实是靠服务层(SSH 用户、Web 前端、钩子)拦截操作,而钩子本身可以被绕过。
容易踩的坑:update 钩子里用 git rev-list 检查提交内容,但没加 --max-count=1,导致大仓库 push 时超时被 kill;或者钩子里调用外部命令没写绝对路径,SSH 环境下 $PATH 不包含 /usr/local/bin。
- 钩子只能拦住
git push,拦不住直接ssh user@server 'cd /repo && git reset --hard' - 若需分支保护,必须配合服务层(如 Gitea 的 protected branch 设置),纯 Git 钩子做不到可靠防护
- 所有钩子脚本第一行必须是
#!/bin/bash(不是sh),且用绝对路径调用命令,例如/usr/bin/git
真正的难点不在怎么搭起来,而在于弄清每层权限边界在哪里——SSH 用户能干啥、钩子能拦住啥、HTTP 服务又暴露了啥。很多问题不是配置错了,是误以为某一层有它其实没有的能力。











