Git 服务器搭建完全指南 / 第 3 章 - Gitolite 权限管理
第 3 章 - Gitolite 权限管理
Gitolite 是基于 Perl 的 Git 权限管理工具,通过一个配置文件集中管理所有仓库和用户的访问权限,无需为每个用户创建系统账号。
3.1 Gitolite 核心概念
工作原理
开发者 gitolite 服务器
│ │
│── SSH 连接 ──────────►│ git 用户
│ (公钥认证) │ │
│ │ ├── ~/.ssh/authorized_keys
│ │ │ (每行对应一个用户的公钥)
│ │ │ 每行的 command= 指向 gitolite-shell
│ │ │
│ │ ├── gitolite-shell
│ │ │ ├── 验证用户身份(通过 SSH 公钥)
│ │ │ ├── 查询权限配置
│ │ │ └── 允许或拒绝操作
│ │ │
│ │ └── repositories/
│ │ ├── project-a.git
│ │ └── project-b.git
│ │
│◄─── 允许/拒绝 ────────│
与第 2 章方案的对比
| 特性 | 裸仓库 + SSH | Gitolite |
|---|---|---|
| 用户管理 | 系统用户或共享 git 用户 | 虚拟用户(映射到 SSH 公钥) |
| 权限粒度 | 目录级别 | 仓库级别 + 分支级别 |
| 权限配置 | 分散在文件系统各处 | 集中在一个配置文件 |
| 新增仓库 | 手动 git init --bare | 配置文件声明即自动创建 |
| Web 界面 | 无 | Gitweb 可选集成 |
| 依赖 | 无 | Perl |
3.2 安装 Gitolite
3.2.1 前置条件
# 确认 Perl 已安装
perl --version
# 确认 Git 已安装
git --version
# 如未安装
sudo apt install perl git -y
3.2.2 创建专用用户
# 创建 gitolite 管理用户(名为 git)
sudo adduser \
--system \
--shell /bin/bash \
--group \
--home /home/git \
git
3.2.3 安装 Gitolite
# 切换到 git 用户
sudo -u git bash
# 克隆 gitolite 源码
cd /home/git
git clone https://github.com/sitaramc/gitolite.git
# 安装到 ~/bin
mkdir -p /home/git/bin
/home/git/gitolite/install -to /home/git/bin
# 确认安装
/home/git/bin/gitolite setup -h
# 显示帮助信息即为成功
exit
3.2.4 初始化 Gitolite
# 在管理员的工作电脑上,先确认有 SSH 公钥
cat ~/.ssh/id_ed25519.pub
# ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAA... admin@workstation
# 将管理员公钥上传到服务器
scp ~/.ssh/id_ed25519.pub git@server:/tmp/admin.pub
# 在服务器上初始化 gitolite
sudo -u git bash
cd /home/git
/home/git/bin/gitolite setup -pk /tmp/admin.pub
exit
# 输出类似:
# Initialized empty Git repository in /home/git/repositories/gitolite-admin.git/
# Initialized empty Git repository in /home/git/repositories/testing.git/
# WARNING: /home/git/.ssh/authorized_keys missing; creating it...
# INFO: creating /home/git/repositories ...
重要: 初始化时传入的公钥对应的用户将成为 Gitolite 管理员,拥有
gitolite-admin仓库的读写权限。
3.2.5 管理员克隆管理仓库
# 在管理员的工作电脑上
git clone git@server:gitolite-admin
cd gitolite-admin
ls -la
# conf/ # 权限配置目录
# keydir/ # 用户公钥目录
3.3 权限配置详解
3.3.1 配置文件结构
gitolite-admin/conf/gitolite.conf 是核心配置文件:
# 编辑配置
cd gitolite-admin
vim conf/gitolite.conf
3.3.2 基础语法
# conf/gitolite.conf
# 仓库定义(支持通配符)
repo project-a
RW+ = alice bob # alice 和 bob 可以读写(含强制推送)
R = charlie # charlie 只能读取
repo project-b
RW = alice # alice 可以读写(不允许强制推送)
RW = bob
R = @all # 所有人可读
repo docs
RW+ = alice
R = @all
# 权限符号说明:
# R = 只读(clone/fetch)
# RW = 读写(clone/fetch/push,不允许非快进推送)
# RW+ = 读写(允许非快进推送/强制推送/删除分支)
# - = 拒绝
3.3.3 用户组
# 定义用户组
@frontend = alice bob
@backend = charlie david
@devops = eve
@admins = alice charlie
# 使用 @all 代表所有用户
# 在仓库配置中使用组
repo web-app
RW+ = @admins
RW = @frontend
R = @backend
repo api-server
RW+ = @admins
RW = @backend
R = @frontend
repo infra-tools
RW+ = @devops
R = @admins
3.3.4 仓库分组(前缀匹配)
# 使用仓库组简化配置
@frontend-repos = web-app shared-ui component-lib
@backend-repos = api-server auth-service data-pipeline
# 批量设置权限
repo @frontend-repos
RW+ = @admins
RW = @frontend
repo @backend-repos
RW+ = @admins
RW = @backend
3.3.5 通配符仓库
适用于需要动态创建仓库的场景:
# 用户可以创建以自己名字为前缀的仓库
# 例如 alice 创建 alice/sandbox, alice/experiment
repo CREATOR/[a-zA-Z].*
C = @all # @all 中的用户可以创建
RW+ = CREATOR # 创建者拥有完全读写权限
R = @all # 其他人只读
# 管理员可以创建以 team/ 为前缀的仓库
repo team/[a-zA-Z].*
C = @admins
RW+ = @admins
RW = MEMBERS
创建通配符仓库:
# 用户在客户端创建自己的仓库
git clone git@server:alice/sandbox
# 如果仓库不存在,会自动创建
# 或者通过 push 创建
mkdir sandbox && cd sandbox
git init
git remote add origin git@server:alice/sandbox
git push origin master
3.3.6 分支级权限控制
repo production-code
RW+ = @admins
RW main = @senior-dev # 只有高级开发者能推送到 main
RW dev = @all-dev # 所有开发者能推送到 dev
RW feature/ = @all-dev # 所有开发者能推送到 feature/* 分支
RW release/ = @release-managers # 只有发布管理员能推送到 release/*
R = @all # 其他人只读
3.3.7 完整配置示例
# gitolite.conf - 企业级配置示例
# ============ 用户组定义 ============
@admin-group = alice
@team-frontend = alice bob
@team-backend = charlie david
@team-devops = eve
@contractors = frank
# ============ 仓库组定义 ============
@core-repos = web-app api-server shared-lib
@infra-repos = terraform ansible docker-images
# ============ 管理仓库 ============
repo gitolite-admin
RW+ = @admin-group
# ============ 核心项目 ============
repo @core-repos
RW+ = @admin-group
RW main = @team-frontend @team-backend
RW dev = @team-frontend @team-backend
RW feature/= @team-frontend @team-backend
R = @contractors
# ============ 基础设施 ============
repo @infra-repos
RW+ = @team-devops
RW main = @admin-group
R = @team-frontend @team-backend
# ============ 文档 ============
repo docs
RW+ = @admin-group
RW = @team-frontend @team-backend @team-devops
# ============ 个人沙箱 ============
repo sandbox/[a-zA-Z].*
C = @team-frontend @team-backend
RW+ = CREATOR
R = @admin-group
3.3.8 提交配置
cd gitolite-admin
# 编辑配置
vim conf/gitolite.conf
# 添加用户公钥(文件名即用户名)
cp /path/to/bob.pub keydir/bob.pub
cp /path/to/charlie.pub keydir/charlie.pub
# 提交并推送
git add conf/ keydir/
git commit -m "Add repositories and users"
git push origin main
# 推送后 gitolite 会自动:
# 1. 解析新配置
# 2. 创建新仓库(如果有的话)
# 3. 更新 authorized_keys
# 4. 输出处理结果
3.4 用户管理
3.4.1 添加用户
# 1. 让用户提供 SSH 公钥
# 用户执行: cat ~/.ssh/id_ed25519.pub
# 2. 将公钥添加到 keydir(文件名为用户名.pub)
cd gitolite-admin
cp /path/to/new-user.pub keydir/newuser.pub
# 3. 在 conf/gitolite.conf 中添加权限
# 4. 提交推送
git add keydir/ conf/
git commit -m "Add newuser"
git push
3.4.2 删除用户
# 1. 删除公钥文件
rm keydir/departing-user.pub
# 2. 从配置中移除权限
# 3. 提交推送
git add -A
git commit -m "Remove departing-user"
git push
3.4.3 一个用户多个设备
# 用户在不同设备上使用不同的 SSH 密钥
# 在 keydir 中使用相同用户名,后缀区分设备
keydir/
├── [email protected]
├── [email protected]
└── [email protected]
# 在 gitolite.conf 中使用通配符或短名
# 方式一:使用 USERNAME 通配符
# Gitolite 会将 alice@laptop, alice@desktop 都识别为 "alice"
# 方式二:手动在配置中写完整名
# @team = alice@laptop alice@desktop
推荐方式: 让 Gitolite 自动处理。只要公钥文件名以
alice@开头,Gitolite 会将其映射到用户alice。
3.4.4 查看用户信息
# 在服务端查看
sudo -u git /home/git/bin/gitolite info -u alice
# 输出:
# C R W alice/sandbox
# - RW+ gitolite-admin
# R RW project-a
3.5 Gitolite 钩子(Hooks)
Gitolite 自身的钩子机制与 Git 原生钩子有所不同。
3.5.1 Gitolite VREF(Virtual Ref)
VREF 是 Gitolite 特有的扩展机制,类似于服务端 pre-receive 钩子,但更灵活。
# 创建自定义 VREF
sudo -u git tee /home/git/.gitolite/hooks/common/VREF/limit-push-size << 'VREF'
#!/bin/bash
# VREF: 限制推送大小
# 获取推送信息
while read oldrev newrev refname; do
# 跳过删除操作
if [ "$newrev" = "0000000000000000000000000000000000000000" ]; then
continue
fi
# 计算推送的对象大小
size=$(git rev-list --objects "$oldrev".."$newrev" | \
git cat-file --batch-check='%(objectsize)' | \
awk '{sum+=$1} END {print sum}')
max_size=$((100 * 1024 * 1024)) # 100MB
if [ "$size" -gt "$max_size" ]; then
echo "ERROR: Push too large ($((size / 1024 / 1024))MB > 100MB)"
exit 1
fi
done
exit 0
VREF
sudo chmod +x /home/git/.gitolite/hooks/common/VREF/limit-push-size
在 gitolite.conf 中使用 VREF:
repo project-a
RW+ = @all
- VREF/limit-push-size = @all
3.5.2 Git 原生钩子
Gitolite 管理的仓库也可以使用标准 Git 钩子:
# 在仓库的 custom hooks 目录中添加
sudo -u git mkdir -p /home/git/.gitolite/hooks/common
# 创建 post-receive 钩子(推送后通知)
sudo -u git tee /home/git/.gitolite/hooks/common/post-receive << 'HOOK'
#!/bin/bash
# 推送后发送通知
while read oldrev newrev refname; do
branch=$(echo "$refname" | sed 's|refs/heads/||')
if [ "$oldrev" = "0000000000000000000000000000000000000000" ]; then
action="created"
elif [ "$newrev" = "0000000000000000000000000000000000000000" ]; then
action="deleted"
else
action="updated"
fi
# 发送通知(示例:写入日志)
echo "$(date): $GL_USER $action branch $branch in $GL_REPO" >> /var/log/git-push.log
# 可以集成 Webhook、邮件、企业微信等
done
HOOK
sudo chmod +x /home/git/.gitolite/hooks/common/post-receive
3.5.3 钩子与 VREF 对比
| 特性 | Git 原生钩子 | Gitolite VREF |
|---|---|---|
| 执行时机 | pre-receive, update, post-receive | 类似 pre-receive |
| 用户信息 | 不直接提供 | 通过 $GL_USER 获取 |
| 仓库信息 | 需要自己获取 | 通过 $GL_REPO 获取 |
| 配置方式 | 放在仓库 hooks/ 目录 | 在 gitolite.conf 中引用 |
| 适用场景 | 通知、部署、日志 | 权限检查、策略执行 |
3.6 高级功能
3.6.1 Gitweb 集成
Gitolite 可以控制哪些仓库在 Gitweb 中可见:
# 在 gitolite.conf 中添加
repo project-a
RW+ = alice bob
R = charlie
R = gitweb # 在 Gitweb 中可见
repo internal-project
RW+ = @admins
# 不添加 gitweb 权限 = 在 Gitweb 中不可见
3.6.2 仓库模板
# 定义默认权限模板
# 新建的仓库会自动继承这些规则
repo @all
# 禁止非快进推送到 main
- VREF/NAME/refs/heads/main = WILDUSER @all
3.6.3 环境变量和自定义配置
# ~/.gitolite.rc 中的关键配置
sudo -u git vim /home/git/.gitolite.rc
# 关键配置项
%RC = (
# 仓库根目录
GL_REPO_BASE => "repositories",
# 日志设置
GL_LOGT => 'gitolite.log',
# 启用的钩子和 VREF
LOCAL_CODE => {
"hooks/common" => undef,
"VREF" => undef,
},
# 权限拒绝时的详细信息
GIT_CONFIG_KEYS => '.*',
);
3.7 日常运维
3.7.1 查询用户权限
# 查看某个用户的权限
sudo -u git /home/git/bin/gitolite info -u alice
# 查看某个仓库的权限
sudo -u git /home/git/bin/gitolite info -r project-a
3.7.2 审计日志
# 查看操作日志
sudo cat /home/git/.gitolite/logs/gitolite-2026-05.log
# 日志格式示例:
# 2026-05-10 10:23:45 alice project-a W refs/heads/main 1234abc..5678def
# 含义: 时间 用户 仓库 权限 分支 提交范围
3.7.3 常用管理命令
# 重新编译配置(配置修改后建议执行)
sudo -u git /home/git/bin/gitolite compile
# 重新生成 authorized_keys
sudo -u git /home/git/bin/gitolite trigger POST_COMPILE
# 查看所有仓库
sudo -u git /home/git/bin/gitolite query-rc REPO_BASE
3.8 业务场景示例
场景:典型企业权限模型
# 企业级权限配置
@admins = cto
@leads = teamlead-a teamlead-b
@senior = senior-dev-1 senior-dev-2
@junior = junior-dev-1 junior-dev-2 junior-dev-3
@qa = qa-lead qa-tester
# 核心产品(严格分支保护)
repo product/.*
RW+ = @admins
RW main = @leads
RW dev = @leads @senior
RW feature/ = @leads @senior @junior
RW bugfix/ = @leads @senior @junior
RW release/ = @leads @qa
R = @qa
# 实验项目(宽松权限)
repo experiment/.*
C = @leads @senior
RW+ = CREATOR
R = @admins
3.9 扩展阅读
本章小结
| 学到了什么 | 关键要点 |
|---|---|
| 安装方式 | 克隆源码、install 脚本、setup 初始化 |
| 权限配置 | gitolite.conf 集中管理、用户组、仓库组、通配符 |
| 分支级控制 | RW/RW+/R 可限定到具体分支或分支前缀 |
| 钩子机制 | VREF 实现策略检查、Git 原生钩子实现通知部署 |
| 用户管理 | 通过 keydir/ 添加公钥,虚拟用户映射 |
进阶方向: Gitolite 虽然权限管理强大,但缺少 Web 界面、Issue 管理、Code Review 等功能。如果团队需要完整的代码托管平台,请继续阅读 Gitea 和 GitLab 章节。
下一章:第 4 章 - Gitea 轻量平台 — 使用 Gitea 搭建功能丰富的代码托管平台。