【Gerrit Patch】批量下载 Gerrit 提交的 Patch
- [一、ssh 方案](#一、ssh 方案)
-
- [1.1 查看 Gerrit 的服务器地址和端口](#1.1 查看 Gerrit 的服务器地址和端口)
- [1.2 gerrit query 命令查询](#1.2 gerrit query 命令查询)
- [二、curl 方案](#二、curl 方案)
-
- [2.1 Gerrit REST API 介绍](#2.1 Gerrit REST API 介绍)
- [2.2 Gerrit REST API 使用](#2.2 Gerrit REST API 使用)
- [三、shell 脚本批处理](#三、shell 脚本批处理)
一、ssh 方案
1.1 查看 Gerrit 的服务器地址和端口
查看远程仓库URL
最直接的方法是查看本地Git仓库中配置的远程仓库地址:
bash
git remote -v
这条命令会列出所有已配置的远程仓库及其对应的URL。Gerrit服务器的IP和端口通常包含在远程仓库的URL中,格式一般为 ssh://username@ip:port/path/to/repo.git
。
检查Git配置文件
如果通过 git remote -v
获取的信息不够详细,可以直接查看Git配置文件:
bash
cat .git/config
这个文件包含了当前仓库的所有配置信息,其中 [remote "origin"]
或类似的段落会明确显示远程Gerrit服务器的完整URL。
验证SSH连接配置
对于使用SSH协议的Gerrit仓库,还可以检查SSH配置文件中是否定义了Gerrit服务器的别名和连接参数:
bash
cat ~/.ssh/config
如果之前配置过Gerrit连接,这里可能会有类似以下的条目:
bash
Host my-gerrit
HostName 192.168.1.100
Port 29418
User your-username
获取 ssh_info
已经 Gerrit 网址 192.168.1.100
,使用 curl
bash
$ curl http://192.168.1.100:8080/ssh_info
192.168.1.100 29418
1.2 gerrit query 命令查询
知道主机名和端口后就可以要验证您的 SSH 密钥是否正常工作,默认情况下,Gerrit 在 端口 29418,使用与 Web 服务器相同的主机名:
bash
$ ssh -p 29418 fangjian@192.168.1.100
**** Welcome to Gerrit Code Review ****
Hi fangjian, you have successfully connected over SSH.
Unfortunately, interactive shells are disabled.
To clone a hosted Git repository, use:
git clone ssh://fangjian@192.168..1.100:29418/REPOSITORY_NAME.git
Connection to 192.168.0.166 closed.
输入以上日志就说明 SSH 连接成功!
参考文档:Gerrit Code Review - SSH - Command Line Tools
gerrit query
:https://gerrit-documentation.storage.googleapis.com/Documentation/2.13.7/cmd-query.html
gerrit query - 查询使用方式
bash
ssh -p <port> <host> gerrit query
[--format {TEXT | JSON}]
[--current-patch-set]
[--patch-sets | --all-approvals]
[--files]
[--comments]
[--commit-message]
[--dependencies]
[--submit-records]
[--all-reviewers]
[--start <n> | -S <n>]
[--]
<query>
[limit:<n>]
使用示例
bash
$ ssh -p 29418 review.example.com gerrit query --format=JSON --start 42 status:open
bash
# 查看change id: 230d069
ssh -p 29419 fangjian@10.20.40.21 gerrit query --current-patch-set --format=TEXT 230d069
# 获取所有 change id
ssh -p 29419 fangjian@10.20.40.21 gerrit query --format=TEXT owner:fangjian is:open
ssh -p 29419 fangjian@10.20.40.21 gerrit query owner:fangjian --current-patch-set --format=TEXT > changes.txt
# 分页查询
ssh -p 29419 fangjian@10.20.40.21 gerrit query --format=JSON owner:fangjian is:open --current-patch-set --commit-message --start 500 limit:500
由于 gerrit ssh 命令行没有提供下载 patch 的方法,我们只能使用 gerrit query 来查询提交的信息,如 change id
。
二、curl 方案
2.1 Gerrit REST API 介绍
参考文档:Gerrit Code Review - REST API
Query Changes
:https://gerrit-documentation.storage.googleapis.com/Documentation/2.13.7/rest-api-changes.html#list-changes
获取一个修订版的格式化补丁:
bash
GET /changes/{change-id}/revisions/{revision-id}/patch
查询更改,通过提供查询字符串 参数:
bash
GET /changes/
还有其他功能的 API,这里我们只需要使用这2个即可,一个用于有条件的获取 change id
,另一个用于根据 change id 下载 patch。
2.2 Gerrit REST API 使用
访问 Gerrit 的 REST API(而不是使用 Basic Auth
),你需要先获取有效的 Gerrit 登录 Cookie 或者 有效的用户名和密码 ,并将其附加到 curl
请求中。
通过 --cookie
加 cookie
方式
bash
curl --cookie "GerritAccount=aQEfprrnWN9qOAL5rYA391uF.T0AGSWuRW" "http://192.168.0.166:8080/changes/?q=owner:fangjian+status:merged"
通过 -u
加用户名:密码
方式
bash
curl -u "fangjian:xxxx" "http://192.168.0.166:8080/changes/?q=owner:fangjian+status:merged"
使用示例
bash
# 获取所有change id
curl -u "fangjian:Droi*#2036" "http://10.20.40.21:8088/a/changes/?q=owner:fangjian+status:open"
# 分页获取
curl -u "fangjian:Droi*#2036" "http://10.20.40.21:8088/a/changes/?q=owner:fangjian+status:open&n=500&start=0"
# 下载指定change id 的patch file
curl -u "fangjian:xxxx" "http://10.20.40.21:8088/a/changes/22141/revisions/current/patch" | base64 -d > my_patch.patch
三、shell 脚本批处理
bash
#!/bin/bash
# Gerrit 登录信息
GERRIT_HOST="http://10.20.40.21:8088" # Gerrit REST API Host
USERNAME="fangjian" # Gerrit 用户名
PASSWORD="xxxx" # Gerrit 密码
# 输入参数
TARGET_OWNER="fangjian" # 查询的目标用户
OUTPUT_DIR="./gerrit_patch" # 本地保存 Patch 文件的目录
LIMIT=500 # 每次查询的记录条数上限
# 创建保存 Patch 文件的目录
mkdir -p "${OUTPUT_DIR}"
# 初始化分页参数
START=0 # 从 0 偏移,分页获取数据
HAS_MORE_CHANGES=true # 初始化为有更多的变更记录
echo "Fetching changes for owner: ${TARGET_OWNER}..."
# 循环查询直到所有变更记录处理完成
while [ "${HAS_MORE_CHANGES}" = true ]; do
echo "Fetching changes starting from offset: ${START}"
# 调用 Gerrit REST API 获取 Change 列表(分页)
RESPONSE=$(curl -s -u "${USERNAME}:${PASSWORD}" \
"${GERRIT_HOST}/changes/?q=owner:${TARGET_OWNER}&n=${LIMIT}&start=${START}" \
-H "Content-Type: application/json")
# 检查 API 调用是否成功
if [ -z "${RESPONSE}" ]; then
echo "Error: Failed to fetch changes from Gerrit. Exiting..."
exit 1
fi
# 去掉 Gerrit 特有的前缀 )]}'
CLEANED_RESPONSE=$(echo "${RESPONSE}" | sed 's/)]}\x27//')
# 检查是否有数据返回
if [ -z "${CLEANED_RESPONSE}" ] || [[ "${CLEANED_RESPONSE}" == "[]" ]]; then
echo "No changes found. Exiting..."
break
fi
# 解析返回的 JSON 数据,提取必要字段,逐个处理 Change
echo "${CLEANED_RESPONSE}" | jq -c '.[]' | while read -r CHANGE; do
# 提取 Change 的基本信息
CHANGE_ID=$(echo "${CHANGE}" | jq -r '.id') # Change ID
SUBJECT=$(echo "${CHANGE}" | jq -r '.subject') # 变更内容的标题
CREATED=$(echo "${CHANGE}" | jq -r '.created' | awk '{print $1}') # 仅保留日期部分,比如2025-02-24
PROJECT=$(echo "${CHANGE}" | jq -r '.project') # 项目名称
BRANCH=$(echo "${CHANGE}" | jq -r '.branch') # 分支名称
# 对 PROJECT 提取最后一级关键字,如 "documents"
PROJECT_KEY=$(echo "${PROJECT}" | awk -F'/' '{print $NF}')
# 构造安全的文件名规则
SAFE_PROJECT=$(echo "${PROJECT_KEY}" | tr '/:' '-') # 替换 `/` 和非法字符为 `-`
SAFE_BRANCH=$(echo "${BRANCH}" | tr '/:' '-') # 替换 `/` 和非法字符为 `-`
# 特殊字符处理:SUBJECT 允许中文和其他字符,替换非法文件名字符
SAFE_SUBJECT=$(echo "${SUBJECT}" | tr '/\\:*?"<>|&' '_')
# 将创建的 PATCH 文件名标准化
PATCH_FILENAME="${SAFE_PROJECT}-${SAFE_BRANCH}-${CREATED}-${SAFE_SUBJECT}.patch"
echo "Downloading patch for Change-ID: ${CHANGE_ID} -> ${PATCH_FILENAME}"
# 下载 Patch 文件
curl -s -u "${USERNAME}:${PASSWORD}" \
"${GERRIT_HOST}/changes/${CHANGE_ID}/revisions/current/patch" | base64 -d > "${OUTPUT_DIR}/${PATCH_FILENAME}"
# 检查下载是否成功
if [ $? -eq 0 ]; then
echo "Saved patch file: ${OUTPUT_DIR}/${PATCH_FILENAME}"
else
echo "Failed to download patch for Change-ID: ${CHANGE_ID}"
fi
done
# 判断是否还有更多的记录 (通过 REST API `_more_changes` 字段)
if echo "${CLEANED_RESPONSE}" | grep -q '"_more_changes":true'; then
HAS_MORE_CHANGES=true
START=$((START + LIMIT)) # 增加偏移量,获取下一批记录
else
HAS_MORE_CHANGES=false
echo "All changes processed."
fi
done
echo "All patches have been downloaded to: ${OUTPUT_DIR}"