强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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 章方案的对比

特性裸仓库 + SSHGitolite
用户管理系统用户或共享 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/
├── alice@laptop.pub
├── alice@desktop.pub
└── alice@phone.pub

# 在 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 搭建功能丰富的代码托管平台。