Skip to main content
Glama

gitl

Action self-test

面向 CLI 和 CI 的 AI 驱动的 git 历史审查工具。 gitl(git-log-lens)读取仓库的 git 历史,并通过 LLM 将其转化为结构化的工程产物:

  • gitl review <range> — 对提交范围 / PR 进行 AI 审查,并提供机器可读的风险评分(low|medium|high),用于 CI 门禁(--fail-on=high → 退出码 2);实时将 token 流式输出到终端;磁盘上的 LLM 响应缓存,并可选共享远程缓存用于 CI;自定义系统提示模板;--staged 在 git commit 之前审查暂存(未提交)的更改(也可作为 pre-commit 钩子 使用)。

  • gitl changelog [<range>] — 生成 Keep a Changelog 风格的变更日志,按 conventional commits 分组(默认从最后一个标签到 HEAD);默认确定性输出,--ai 可选地使用模型将其重写为可读的发布说明散文;

  • gitl digest [--days=N] [--repos=a,b,c] — 按作者/主题/文件生成活动摘要,支持并行处理多个仓库;交互式 TUI 查看器(--tui)。

一个简洁的 CLI 二进制文件加上一个 GitHub Action 包装器——无需服务器、数据库或托管密钥存储。BYOK(自带密钥)并支持多提供商:OpenAI 兼容 API、Ollama(本地/自托管)、Azure OpenAI、原生 Anthropic(Claude)、Google Gemini。无遥测。

状态: v0.6.2 已发布——所有三个命令都能在真实仓库上工作,并支持所有三种输出格式(md|text|json)。该 Action 将 AI 审查作为置顶 PR 评论发布,并根据风险评分进行门禁。发布二进制文件是交叉编译的,经过 cosign 签名,并受 SLSA L3 构建来源保护(参见 VERIFY.md)。

快速开始

需要 Go 1.22+ 和 git 在 PATH 中。

# build
go build ./...

# AI review of a commit range — streams tokens to the terminal in real time
GITL_API_KEY=sk-... go run ./cmd/gitl review HEAD~5..HEAD

# no key = deterministic offline review (heuristic risk, no network call)
go run ./cmd/gitl review HEAD~5..HEAD

# review staged (not yet committed) changes before `git commit`
go run ./cmd/gitl review --staged

# review a GitHub PR by number — requires the `gh` CLI (installed + authenticated);
# resolves base/head via gh, fetches `pull/N/head` locally when needed, and reviews
# the merge-base diff (base...head), same as GitHub shows
go run ./cmd/gitl review pr/42

# machine-readable output for CI + risk gating
go run ./cmd/gitl review HEAD~5..HEAD --format=json
go run ./cmd/gitl review HEAD~5..HEAD --fail-on=high   # exit code 2 on high risk
# exit codes: 0 = ok (risk below --fail-on), 1 = tool/runtime error (git/LLM/
# config failure), 2 = the --fail-on risk gate triggered — CI can branch on 2

# estimate cost without making an API call
go run ./cmd/gitl review HEAD~5..HEAD --dry-run

# custom system-prompt template (e.g. your team's review policy) — set via
# config only (prompt.system_template_file); there is no --system-template flag
# see Configuration → Custom templates below

# skip the on-disk LLM cache (always call the model)
go run ./cmd/gitl review HEAD~5..HEAD --no-cache

# disable streaming (non-interactive, buffered output)
go run ./cmd/gitl review HEAD~5..HEAD --no-stream

# suppress the informational offline-mode notice on stderr (errors and the
# review output are unaffected) — also via GITL_QUIET=1 or output.quiet: true
go run ./cmd/gitl review HEAD~5..HEAD --quiet

# changelog from last tag (or full history if no tags) — no LLM by default
go run ./cmd/gitl changelog
go run ./cmd/gitl changelog v1.2.0..HEAD --format=json

# AI changelog: the model rewrites the grouped result as release-note prose and
# reclassifies significant non-conventional commits out of "Other". Without an API
# key (or on a malformed model response) it falls back to the deterministic
# changelog with a warning — never fails. --dry-run/--max-cost-usd/--no-cache work
# the same as for review.
GITL_API_KEY=sk-... go run ./cmd/gitl changelog --ai

# activity summary for the last N days — no LLM
go run ./cmd/gitl digest --days=14

# multi-repo digest: runs in parallel; one unreachable repo does not fail the rest
go run ./cmd/gitl digest --repos=../service-a,../service-b --format=json

# interactive TUI viewer for digest (requires a TTY)
go run ./cmd/gitl digest --days=14 --tui

go run ./cmd/gitl version
go run ./cmd/gitl --help

# tests
go test ./...

安装:

# Go toolchain
go install github.com/akomyagin/gitl/cmd/gitl@latest

# Homebrew (macOS/Linux)
brew install akomyagin/tap/gitl

# npm — downloads the prebuilt binary for your platform from GitHub Releases
# and verifies its SHA256 checksum (no Go toolchain needed).
npx gitl-cli review HEAD~5..HEAD   # or: npm install -g gitl-cli

# Or download a signed release binary from GitHub Releases (see VERIFY.md)

Shell 补全

gitl 附带 cobra 生成的 bash、zsh、fish 和 PowerShell 补全。

Homebrew 安装会自动安装 bash/zsh/fish 补全(发布归档也包含在 completions/ 下)。否则,按需启用:

# bash (current shell)
source <(gitl completion bash)
# bash (persistent) — Linux
gitl completion bash > /etc/bash_completion.d/gitl
# zsh (persistent)
gitl completion zsh > "${fpath[1]}/_gitl"
# fish
gitl completion fish > ~/.config/fish/completions/gitl.fish
# PowerShell
gitl completion powershell | Out-String | Invoke-Expression

具有固定值集合的标志——--format(md|text|json)、--fail-on(never|low|medium|high)和 --provider——会补全其允许的值。

本地多提供商测试(Ollama)

docker-compose.yml 仅启动开发依赖——一个用于测试多提供商 LLM 客户端的本地 Ollama 实例(gitl 本身不进行容器化):

docker compose up ollama

Related MCP server: grippy-code-review

配置

快速路径:gitl init 在仓库根目录写入一个带注释的入门 .gitl.yaml(除非使用 --force,否则拒绝覆盖现有文件;--output 可写入其他位置)。编辑它而不是从本节复制粘贴——以下内容是完整参考。

两个级别,按优先级合并: 标志 > 环境变量 > .gitl.yaml(仓库)> ~/.config/gitl/config.yaml(个人)。 仓库级别的 .gitl.yaml 作为团队共享策略提交(风险阈值、排除路径、变更日志类别)。如果没有密钥,gitl 将以确定性离线模式运行。

在离线模式下——或者当真实模型省略了有效的风险块且 gitl 回退到启发式时——风险头部会标注 *(heuristic)*(在 --format=json 中为 "heuristic": true),这样确定性评分就不会被误认为是模型自身的判断。

提供商(llm.provider)

# OpenAI-compatible API (default)
llm:
  provider: "openai"
  api_key: ""            # or env GITL_API_KEY
  base_url: "https://api.openai.com/v1"
  model: "gpt-4o-mini"

# Ollama — local/self-hosted, no key, free
llm:
  provider: "ollama"
  base_url: "http://localhost:11434/v1"
  model: "llama3.1"

# Azure OpenAI — custom auth/endpoint format
llm:
  provider: "azure_openai"
  api_key: ""             # or env GITL_API_KEY
  model: "gpt-4o-mini"    # used only for cost estimation
  azure_openai:
    endpoint: "https://<resource>.openai.azure.com"
    deployment: "<deployment-name>"
    api_version: "2024-08-01-preview"

# Anthropic (native Claude Messages API)
llm:
  provider: "anthropic"
  api_key: ""            # or env GITL_API_KEY
  model: "claude-sonnet-4-6"
  # base_url optional; defaults to https://api.anthropic.com

# Google Gemini (Google AI Studio)
llm:
  provider: "gemini"
  api_key: ""            # or env GITL_API_KEY
  model: "gemini-2.5-flash"
  # base_url optional; defaults to https://generativelanguage.googleapis.com/v1beta

流式输出(output.stream)

在交互式审查时(TTY 上的 md 或 text 格式),gitl 会实时将 token 流式输出到终端——无需等待完整响应。流式输出默认开启,并在 CI(非 TTY 标准输出)、--format=json 以及配置了自定义 output.template_file 时自动关闭(模板需要完整响应,因此审查会被缓冲并通过模板渲染)。

流式输出目前仅针对 OpenAI 兼容提供商(openai / ollama / azure_openai)实现。对于原生 anthropic 或 gemini 提供商,gitl 会透明地产生与单个缓冲响应相同的审查结果(无逐 token 输出),无论 output.stream / --no-stream 如何设置。

output:
  stream: true   # default; set false to always buffer

按调用禁用:gitl review HEAD~5..HEAD --no-stream

颜色(output.color)

在交互式终端上,gitl review 会对头部中的风险级别进行着色(HIGH 红色,MEDIUM 黄色,LOW 绿色)。当标准输出不是 TTY(管道、CI 日志)时,颜色会自动关闭,并且永远不会出现在 --format=json 输出中。优先级从高到低:

  1. 设置了 NO_COLOR 环境变量(任何值,甚至为空)——颜色关闭(no-color.org);

  2. 配置中的 output.color: false(或 GITL_OUTPUT_COLOR=false)——颜色关闭;

  3. 标准输出不是 TTY——颜色关闭;

  4. 否则——颜色开启。

output:
  color: true   # default; set false to disable ANSI color

安静模式(output.quiet)

如果没有 API 密钥,review 每次运行都会向 stderr 打印一条信息性通知“使用确定性离线审查”(changelog --ai 也会打印类似的回退通知)。在已知的离线上下文中——最明显的是 pre-commit 钩子,它会在每次提交时触发——该横幅是噪音。使用以下任一方式抑制它(每一层都可以独立开启抑制):

  1. review / changelog 上的 --quiet 标志;

  2. 设置了 GITL_QUIET 环境变量(任何值,甚至为空);

  3. 配置中的 output.quiet: true(或 GITL_OUTPUT_QUIET=true)。

--quiet 仅静默信息性横幅:错误、渲染的审查/变更日志(在标准输出上)以及 --fail-on 门禁永远不会受到影响。

output:
  quiet: false   # default; set true to suppress the offline notices

LLM 响应缓存(cache)

gitl review 将模型响应缓存到磁盘(提供商 + 模型 + 提示的 SHA-256)。相同的差异会立即重用缓存结果,无需 API 调用或费用。

cache:
  enabled: true    # default
  ttl_hours: 24    # entries older than this are ignored

缓存位于 ~/.cache/gitl/review/(符合 XDG 规范)。按调用禁用:gitl review HEAD~5..HEAD --no-cache

在 --format=json 中,每个审查产物都携带附加的运行元数据(schema_version 保持为 1;早于它的消费者会看到相同的文档加上两个新键):

{
  "duration_ms": 1234,
  "cache": { "hit": true, "tier": "local" }
}
  • duration_ms — 整个审查运行的墙钟时间,以毫秒为单位(缓存命中仍会报告一个真实的、通常很小的数字)。

  • cache.hit — 此审查是否来自 LLM 响应缓存而不是新的模型调用。

  • cache.tier — 本次运行生效的缓存拓扑:none(离线模式、--no-cache、cache.enabled: false 或 ttl_hours <= 0)、local(仅磁盘)或 tiered(磁盘 + 远程)。它报告配置的模式,而不是哪个后端提供了特定的命中。

故意没有 usage(token 计数)字段:gitl 不解析响应中的提供商使用情况,永久为空的字段比缺失更糟糕。当使用情况解析落地时,它将被添加——以附加方式,不增加 schema 版本。

共享远程缓存(cache.remote)— 可选加入

可选加入,默认关闭,自带后端: gitl 从不托管服务,并且在您配置之前不会向任何缓存发出网络请求。适用于 CI 冷启动——每个运行器都从空磁盘开始,但共享的 HTTP KV 端点允许一个运行器重用另一个运行器对相同差异的审查。

cache:
  enabled: true
  ttl_hours: 24
  remote:                     # opt-in shared cache for CI cold starts (off by default)
    url: https://cache.example.com/gitl   # your endpoint; gitl hosts nothing
    token_env: GITL_REMOTE_CACHE_TOKEN    # env var holding an optional bearer token
    timeout_ms: 3000

配置后,本地磁盘缓存保持为第一层:读取先检查磁盘,然后检查远程(远程命中会回填到磁盘);写入同时进行。

协议是一个基于 HTTP 的简单键值存储——任何静态对象存储或小型处理器都可以:

  • GET {url}/{key} → 200 并返回 JSON 条目主体,或 404 = 未命中。任何其他状态、网络错误或超时都视为未命中。

  • PUT {url}/{key} 并将 JSON 条目作为请求主体(Content-Type: application/json)→ 任何 2xx = 已存储。

  • 如果 token_env 指定了一个具有非空值的环境变量,则两个请求都携带 Authorization: Bearer <token>。token 本身永远不会从配置文件中读取(与 GITL_API_KEY 相同的纪律)。

  • 键是 64 字符的十六进制 SHA-256 字符串;值对服务器是不透明的。

安全契约: 任何远程故障(超时、5xx、端点不可达)都会静默降级为本地缓存 / 无缓存——它永远不会使审查失败。存储的条目仅包含模型的响应,由不透明的哈希键控:差异和提示文本永远不会到达远程缓存。早于 ttl_hours 的条目在客户端被忽略,无论服务器返回什么。

风险趋势(policy.risk_log_enabled)

每次 gitl review 运行都会将其风险结果(级别、范围、提供商、时间戳)追加到本地 JSONL 日志:$XDG_DATA_HOME/gitl/risk-history.jsonl(默认 ~/.local/share/gitl/risk-history.jsonl;Windows 上为 %AppData%\gitl\)。gitl digest 会读回它并显示每个仓库的 “风险趋势(最近 N 天)” 部分——按级别划分的审查数量、高风险方向(窗口的最近一半与较早一半相比)以及最近几次审查。在 --format=json 中,它作为可选的 risk_trend 字段出现(schema_version 保持为 1;早于它的消费者会看到相同的文档)。没有历史的仓库会直接省略该部分。

审查通过其 origin 远程 URL 与仓库关联(当没有 origin 时回退到工作树路径)。

限制: 历史记录仅限本地机器——它不会在 CI 运行器之间持久化(每个运行器都从冷磁盘开始),因此趋势是本地开发人员使用的功能,而不是 CI 的功能。

在配置中选择退出(没有 CLI 标志):

policy:
  risk_log_enabled: false

自定义模板(prompt.*_template_file / output.template_file)

独立的、仅配置的覆盖(它们都没有 CLI 标志):

  • prompt.system_template_file — 您自己的审查系统提示,用于引导模型的关注点(安全清单、架构约束、团队规则)。仅由 gitl review 使用:

    prompt:
      system_template_file: "./review-policy.md"   # path relative to CWD

    审查系统提示模板可以访问 {{ .Commits }}、{{ .Diff }}、{{ .Range }}、{{ .Staged }}(参见 internal/prompt/templates.go)。

  • prompt.changelog_system_template_file — 您自己的变更日志系统提示,仅由 gitl changelog --ai 使用:

    prompt:
      changelog_system_template_file: "./changelog-policy.md"   # path relative to CWD

    变更日志系统提示模板可以访问 {{ .Commits }}、{{ .Range }}、{{ .Grouped }}——不是 {{ .Diff }}:changelog --ai 基于提交元数据工作,没有差异,使用 .Diff 的审查形状模板在这里会失败。这正是两个键分开的原因:每个命令只读取自己的键,并且可以单独设置其中一个而不设置另一个。

  • output.template_file — 您自己的**md 格式渲染模板**,用于完成的审查产物:

    output:
      template_file: "./review-output.tmpl"   # path relative to CWD

    输出模板具有 internal/render/render.go 中的渲染模板函数(render.TemplateFuncs())。

信任说明: prompt.*_template_file/output.template_file 键可以由仓库级别的 .gitl.yaml 设置,而不仅仅是您的个人配置——因此对您不控制的克隆仓库运行 gitl review 可能会将其指向该同一仓库内的模板。这是团队共享审查策略的预期机制,而不是错误:这里的 text/template 无法读取任意文件或执行代码,但对待不受信任的仓库的 .gitl.yaml 应像对待其 .git/hooks 或构建脚本一样谨慎。

GitHub Action

gitl 可以作为 GitHub Action 接入:它会 AI 审查拉取请求的提交,并发布带有风险评分的评论,可选地在超过阈值时阻止合并。该 Action 从源代码构建 gitl(在固定版本上执行 go install)。如果您愿意,也可以从 GitHub Marketplace 添加。

将 .github/workflows/gitl-review.yml 添加到您的仓库:

name: gitl review
on:
  pull_request:

permissions:
  contents: read          # for checkout
  pull-requests: write    # to post the review comment

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
        with:
          fetch-depth: 0    # required: without full history base..head won't resolve

      - uses: akomyagin/gitl@v0.6.2
        with:
          gitl-api-key: ${{ secrets.GITL_API_KEY }}   # BYOK, see below
          fail-on: high                               # optional: block merge on high risk

安全最佳实践:

  • 仅通过 secrets.* 提供密钥。 gitl-api-key 来自 secrets.GITL_API_KEY(在 Settings → Secrets and variables → Actions 下设置),绝不硬编码在 YAML 中或提交到仓库。 如果未设置该 secret,Action 将以确定性的离线模式运行(无网络、无成本)。

  • 最小化 permissions:。 只需要 pull-requests: write(用于发布评论)和 contents: read(用于检出)——不要授予更广泛的权限。

  • 必须设置 fetch-depth: 0。 GitHub 在 pull_request 事件中提供 base/head SHA, 但浅克隆无法解析 base.sha..head.sha。

  • fail-on 默认为 never。 该 Action 仅发布评论;除非你显式选择加入 (fail-on: high 等),否则不会阻止合并——与 CLI(--fail-on)的“默认 WARN, 硬性门禁需显式选择加入”原则相同。当门禁触发时,任务以 gitl 的退出码 2(风险门禁) 失败——真正的工具错误以 1 失败,因此下游步骤可以区分“有风险的变更”和“gitl 出错”。

  • Diff 隐私。 在 CI 中,diff 被发送到所配置的任意 LLM 提供商 (默认:兼容 OpenAI 的 API)。对于私有代码,请使用自托管/企业级提供商 (Ollama、Azure OpenAI)——参见上文 Providers。

  • 提供商选择。 默认情况下,Action 使用你配置中的提供商(如果未设置则为兼容 OpenAI 的 提供商)。要指定原生提供商,请传入 provider:(openai|ollama|azure_openai|anthropic|gemini), 以及可选的 model: 和 base-url:,与 gitl-api-key: 一起使用。这三个都是可选的, 省略时会回退到你的 .gitl.yaml/个人配置以及 gitl 的内置默认值——参见上文 Providers。示例:provider: anthropic 并在 secrets.GITL_API_KEY 中提供 Claude 密钥。

  • Secret 掩码。 GitHub 会自动将 runner 日志中的 secrets.* 值掩码为 ***,但这并不是你在自己的工作流步骤中打印密钥的理由。

PR 描述风险摘要(选择加入)

使用 update-pr-description: true(默认 false)时,Action 还会在 PR 描述末尾维护 一个紧凑的风险摘要块——风险行加上指向完整审查评论的链接,每次运行都会更新:

      - uses: akomyagin/gitl@v0.6.2
        with:
          gitl-api-key: ${{ secrets.GITL_API_KEY }}
          update-pr-description: true

这是选择加入的,因为编辑 PR 描述比置顶评论更具侵入性;不需要额外的权限—— 发布评论所需的 pull-requests: write 同样覆盖 PR 正文。该块由 <!-- gitl-review-summary --> 标记对界定,只有标记之间的文本会被替换—— 你在标记之外写的任何内容都不会被触碰。目前仅支持 GitHub(在 Gitea Actions 上被忽略)。

Gitea Actions(实验性)

同一个 action.yml 也可以在 Gitea Actions 上运行—— Gitea 的 runner 执行 GitHub 风格的复合 action,gitl 的 action 在运行时通过 Gitea 的 act_runner 注入到每个任务中的 GITEA_ACTIONS=true 变量来检测平台。 唯一平台相关的部分——发布置顶 PR 评论——通过 Gitea 的 REST API (POST/PATCH /api/v1/repos/{owner}/{repo}/issues/...)使用 curl 完成,而不是 gh CLI(后者只支持 GitHub 的 API)。GitHub 用户不受影响:没有 GITEA_ACTIONS 时,action 的行为与之前完全一致。

将 .gitea/workflows/gitl-review.yml 添加到你的仓库(完整带注释的示例: 本仓库中的 .gitea/workflows/gitl-review.yml):

name: gitl review
on:
  pull_request:

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: https://github.com/actions/checkout@v7
        with:
          fetch-depth: 0
      - uses: https://github.com/akomyagin/gitl@v0.6.2
        with:
          gitl-api-key: ${{ secrets.GITL_API_KEY }}   # BYOK; omit for offline mode

要求:启用 Actions、较新的 act_runner(支持 node24)、以及提供 bash、git、curl、 jq 和 node 的 runner 镜像。GITL_API_KEY 放入 Gitea 的 Actions secrets 中, 绝不写入 YAML——与 GitHub 上相同的 BYOK 规则。

验证状态——在依赖此功能前请先阅读。 基于 curl 的 REST 调用(列出评论、创建、更新、置顶检测)已针对真实的 Gitea 实例 (Docker 中的 gitea/gitea)端到端运行——列表为空 → POST 创建 → 重新列出可找到 → PATCH 更新 → 仍然只有一条评论。这部分按文档所述正常工作。 尚未验证的是周围的 act_runner CI 上下文: GITEA_ACTIONS/GITHUB_API_URL/PR 事件负载在真实工作流运行中是否与假设完全一致 (这是对照 Gitea/act_runner/act-fork 源码交叉检查的,并未在实际任务中运行)。 在有人在真实的 Gitea Actions 中确认端到端绿色运行之前,请将 CI 触发路径视为实验性; 非常欢迎来自真实实例的 bug 报告。

GitLab CI(实验性)

gitl 还附带一个 GitLab CI/CD 组件—— templates/gitl-review.yml——镜像了 GitHub Action 的功能: 它使用 go install 在固定版本上安装 gitl,审查合并请求的范围 ($CI_MERGE_REQUEST_DIFF_BASE_SHA..$CI_COMMIT_SHA),通过共享的平台无关 ci/comment.sh 渲染评论,并通过 GitLab 的 REST API 创建/更新 置顶 MR 评论(与 GitHub/Gitea 上相同的 <!-- gitl-review --> 标记)。该任务仅在合并请求流水线中运行。

该组件通过本仓库的发布时镜像发布在 GitLab CI/CD Catalog 中, 镜像位于 gitlab.com/alkom68/gitl(单向 GitHub → GitLab, 在每个发布标签时推送)。在 gitlab.com 上,将其作为目录组件引入:

# .gitlab-ci.yml (gitlab.com)
include:
  - component: gitlab.com/alkom68/gitl/gitl-review@v0.6.2
    inputs:
      fail_on: "never"      # default; set "high" to block risky MRs
      # max_cost_usd: "0.50"
      # gitl_version: "v0.6.2"

在自托管的 GitLab 实例上,include:component 只能解析来自同一实例的组件—— 请改用 include:remote 直接从 GitHub 引入模板(inputs 适用于远程引入):

# .gitlab-ci.yml (self-hosted GitLab)
include:
  - remote: "https://raw.githubusercontent.com/akomyagin/gitl/v0.6.2/templates/gitl-review.yml"
    inputs:
      fail_on: "never"

设置——两个 CI/CD 变量(Settings → CI/CD → Variables,均需掩码,绝不写入 YAML):

  • GITL_API_KEY — BYOK LLM 密钥。可选:没有它时 gitl 运行确定性的 离线审查(无网络、无成本)。定义项目变量就足够了——它优先于组件空的 gitl_api_key input 默认值。如果改用 input,请传入变量引用 (gitl_api_key: $MY_LLM_KEY),绝不要传字面密钥:input 值会被插值到流水线配置中。

  • GITL_GITLAB_TOKEN — 用于发布 MR 评论的令牌(项目访问令牌或 PAT,api 范围,Reporter 角色或更高;作为 PRIVATE-TOKEN 发送)。如果未设置, 任务会回退到 CI_JOB_TOKEN(JOB-TOKEN 头)——但在大多数 GitLab 配置中,CI_JOB_TOKEN 无权访问 Notes API,因此回退预计会失败 (带有明确的错误消息,而不是静默跳过)。显式设置 GITL_GITLAB_TOKEN 才是可靠路径。

一个完整的带注释自测流水线——也是最接近完整用法示例的内容—— 是 .gitlab-ci-selftest.yml(可作为本仓库 GitLab 镜像中的 .gitlab-ci.yml 运行)。

验证状态——在依赖此功能前请先阅读。 GitLab REST 调用 (列出 MR 评论 + 置顶标记检测、POST 创建、PUT 更新)以及组件 YAML 本身 (spec:/inputs: 插值、带 inputs 的 include:local,通过 CI Lint API 验证) 已针对真实的本地 GitLab CE 实例(Docker 中的 gitlab/gitlab-ce 19.2.0)在真实的合并 请求上端到端验证——列表为空 → POST 创建 → 重新列出可找到 → PUT 更新 → 仍然 只有一条评论——使用了模板中的确切 curl/jq 命令。尚未验证的是实时流水线运行: 真实合并请求流水线中 CI_MERGE_REQUEST_DIFF_BASE_SHA/CI_COMMIT_SHA/CI_JOB_URL 的值是根据 GitLab 文档编写的,而非实际观察到的,并且 CI_JOB_TOKEN 回退被拒绝 是根据 GitLab 的 job-token 允许列表文档记录的,而非复现的。在有人确认端到端绿色运行之前, 请将流水线路径视为实验性;欢迎 bug 报告。

信任说明。 该组件在 gitl_version 处从 GitLab 镜像 (gitlab.com/alkom68/gitl)下载 ci/comment.sh 并执行——没有 校验和/签名检查,与上面紧邻的 go install ...@${gitl_version} 行具有相同的信任边界 (同一仓库、同一引用)。此获取无论组件如何引入都会发生——Catalog 或 include:remote——因为组件引入只附带 YAML 模板,而不附带组件仓库的文件, 因此无法在机制上避免此获取。从发布该组件的同一 GitLab 实例下载 (而不是从 GitHub)可保持同命名空间/同引用,这比跨主机获取更诚实的信任模型。 如果这对你的威胁模型很重要,请将 gitl_version 固定为提交 SHA 而不是标签(标签是可移动的)。

Bitbucket Pipelines(实验性)

Bitbucket 集成以 Pipe 形式提供—— 而 pipe 按定义就是 Docker 镜像,因此与 GitHub/Gitea action 和 GitLab 组件 (纯 YAML 包装器)不同,这是一个自包含镜像: bitbucket-pipe/Dockerfile 构建一个静态的 gitl 二进制文件,并内置共享的 ci/comment.sh 渲染器以及 入口点 bitbucket-pipe/pipe.sh。该 pipe 解析 PR 范围($BITBUCKET_PR_DESTINATION_COMMIT..$BITBUCKET_COMMIT),运行 gitl review --format=json,并通过 Bitbucket Cloud REST API 创建/更新 置顶 PR 评论(与其他平台相同的 <!-- gitl-review --> 标记)。变量参考: bitbucket-pipe/pipe.yml。

镜像状态。 自 v0.5.2 起发布在 Docker Hub 上,名为 alkom68/gitl-review-pipe——发布工作流的 docker-publish 任务在每个发布标签时 推送 :<version> 和 :latest。注册表中只存在 0.5.2 及更高版本: 更早的版本早于发布(0.5.0/0.5.1 标签从未被推送),因此不要固定这些版本。

# bitbucket-pipelines.yml
pipelines:
  pull-requests:
    '**':
      - step:
          name: gitl review
          clone:
            depth: full   # the default depth-50 clone may not contain the PR base commit
          script:
            - pipe: docker://alkom68/gitl-review-pipe:0.6.2
              variables:
                GITL_API_KEY: $GITL_API_KEY                    # BYOK; omit for offline review
                GITL_BITBUCKET_TOKEN: $GITL_BITBUCKET_TOKEN    # posts the PR comment
                # FAIL_ON: "high"        # default "never" — comment only, no gate
                # MAX_COST_USD: "0.50"

设置——两个受保护的仓库/工作区变量(Repository settings → Pipelines → Repository variables;始终以 $VAR 形式引用,绝不在 YAML 中使用字面值):

  • GITL_API_KEY — BYOK LLM 密钥。可选:没有它时 gitl 运行确定性的 离线审查(无网络、无成本)。

  • GITL_BITBUCKET_TOKEN — 用于发布 PR 评论的凭据:具有 pullrequest:write 范围的仓库/项目/工作区访问令牌,作为 Authorization: Bearer 发送。 替代方案:设置 GITL_BITBUCKET_USER + GITL_BITBUCKET_APP_PASSWORD (具有 pullrequest:write 的应用密码)以使用 Basic 认证。如果两者都未配置, pipe 会以明确的错误消息快速失败——在花费任何 LLM 预算之前。

供应链说明(为何这与 GitLab 组件不同)。 该 pipe 不执行任何运行时获取的内容: gitl 二进制文件、ci/comment.sh 和入口点都从单一源码树构建到带版本的镜像中。 GitLab 组件必须在网络上无完整性检查地下载 ci/comment.sh(参见其上面的信任说明); 该 pipe 通过构造方式弥补了这一差距。

验证状态 — 在依赖本工具前请先阅读。 镜像构建和完整的容器内流程已在本地验证:从本仓库执行 docker build,然后针对一个真实的测试 git 仓库、以模拟的 BITBUCKET_* 变量执行 docker run — 离线审查 → 生成正确的 sticky comment.md → 创建评论(POST)、更新 sticky 评论(PUT,仍然恰好一条评论)以及 --fail-on 退出码传播,均针对本地 Bitbucket 评论 API 的 mock 进行了端到端测试;快速失败路径(缺少凭据/PR 变量)和错误范围上的回退提示也已在容器内测试。尚未验证的内容:任何涉及真实 Bitbucket 基础设施的部分 — 针对 api.bitbucket.org 的 REST 调用(请求结构取自 Atlassian 的 API 文档)、真实 PR 流水线中的确切预定义变量(BITBUCKET_PR_DESTINATION_COMMIT 等是文档化的假设,而非实际观测值),以及 Pipelines 如何将克隆挂载到 pipe 容器中。在有人在真实 Bitbucket 工作区上确认一次绿色运行之前,请将实时流水线路径视为实验性功能;欢迎提交 bug 报告。

Pre-commit 钩子(本地)

gitl 附带一个 pre-commit 框架钩子,使得 gitl review --staged --quiet 在每次提交前自动运行 — 本地、离线、默认零成本(钩子清单中默认开启 --quiet,因此离线提示不会在每次提交时重复打印)。

在仓库的 .pre-commit-config.yaml 中添加:

repos:
  - repo: https://github.com/akomyagin/gitl
    rev: v0.6.2   # pin to a released tag
    hooks:
      - id: gitl-review

然后运行 pre-commit install。该框架会自行构建 gitl 二进制文件(language: golang)并将环境缓存在 ~/.cache/pre-commit/ 下,因此构建成本只支付一次,而非每次提交都支付。

如需选择带成本上限的阻塞式钩子:

hooks:
  - id: gitl-review
    args: [--fail-on=high, --max-cost-usd=0.05]   # opt-in: block on high risk, cap cost

在环境中导出 GITL_API_KEY 以获得真实的 AI 审查;没有它,钩子将执行确定性的离线审查(无网络、无成本)。

需要了解的事项:

  • 默认离线。 无 API 密钥、无网络、无每次提交成本。设置 GITL_API_KEY 可选择真实的 AI 审查。

  • 默认不阻塞。 钩子打印审查结果但不会使提交失败 — 与 CLI/Action 相同的"默认 WARN,硬性门禁需显式选择"原则。添加 args: [--fail-on=high] 以阻塞。

  • 延迟。 真实 API 审查需要几秒钟;保持离线以避开热路径,或用 --max-cost-usd 设置上限。

  • Diff 隐私。 使用真实密钥时,暂存的 diff 会发送到你配置的 LLM 提供商 — 对于私有代码,请使用自托管/企业级提供商(Ollama、Azure OpenAI),参见上文 Providers。

  • 抑制离线提示。 清单默认传递 --quiet,因此每次提交时"使用确定性离线审查"的 stderr 提示会被静默;同样的开关也可在 review/changelog 上以 --quiet / GITL_QUIET 使用,或通过 output.quiet: true 在仓库范围内生效(MCP 服务器仅识别 output.quiet/GITL_OUTPUT_QUIET — 它没有命令行标志,因此简短的 GITL_QUIET 别名在那里不适用)。错误和审查输出本身不受影响。

不使用 pre-commit 框架

普通的 git 钩子也可以:

# .git/hooks/pre-commit  (chmod +x)
#!/usr/bin/env bash
set -euo pipefail
# Offline, non-blocking review of staged changes (WARN by default); --quiet
# suppresses the per-commit offline notice on stderr.
gitl review --staged --quiet || true
# To block the commit on high risk instead, replace the line above with:
#   gitl review --staged --quiet --fail-on=high

MCP 服务器

gitl mcp 将 gitl 作为 Model Context Protocol stdio 服务器运行 — 这是与上述 CLI/CI 用法不同的、额外的通道,用于在代理会话(Claude Desktop、Cursor、Windsurf 等)中交互式地使用 gitl,而不是通过 shell 调用。它暴露两个工具:

  • gitl_review — 与 gitl review 相同的审查引擎:range/pr/staged(恰好一个),可选的每次调用 model 覆盖。提供商和端点在设计上于服务器启动时固定:工具调用者是 AI 代理,可能被审查内容中的提示注入所操纵 — 每次调用的 base_url 会让恶意提交重定向请求并泄露真实的 API 密钥。始终返回结构化的 JSON 工件(无 md/text 渲染、无流式输出 — 工具结果是原子的)。risk.level 作为数据返回;MCP 模式中没有 --fail-on,因为没有进程退出码可供门禁。

  • gitl_digest — 与 gitl digest 相同:days(默认 7),可选的 repos。没有显式的 repos 参数时,该工具只摘要服务器的当前工作目录(加上 .gitl.yaml 中配置的 digest.repos,如果配置了的话)— 它绝不会自行遍历任意路径。显式的 repos 参数按原样处理(调用代理已经通过自己的工具拥有文件系统访问权限;这不是访问控制边界,只是一个"不让用户意外"的默认行为)。

添加到你的 MCP 客户端配置中(Claude Desktop、Cursor 等):

{
  "mcpServers": {
    "gitl": {
      "command": "gitl",
      "args": ["mcp"]
    }
  }
}

配置在启动时以与普通命令相同的方式加载一次(.gitl.yaml + 个人配置 + GITL_* 环境变量,从启动 gitl mcp 的目录加载)。没有密钥时,工具调用以与 CLI 相同的确定性离线模式运行。stdout 保留给 MCP 协议 — 那里永远不会写入任何人类可读的内容;警告输出到 stderr。

许可证

MIT。

Related MCP Connectors

Related MCP Servers