【工具使用------代码版本管理】Gerrit
一般企业内部都会使用到这个工具,我这边学习整理一下gerrit的用法,欢迎大佬们批评指正~
Gerrit 是一个基于 Git 的代码评审系统所有代码提交必须经过 review 才能合入
使用 Change + Patch Set 管理代码修改过程
通过 refs/for/* 提交代码进入审核流程
常与 CI 系统(如 Jenkins)集成
GitHub / GitLab 的区别
| 工具 | 核心特点 |
|---|---|
| GitHub / GitLab | 代码托管 + PR/MR(审核是建议性的) |
| Gerrit | 审核是必须的,不通过不能合入 |
Gerrit 有一个非常核心的概念:一切提交都必须被 Review
你的代码流程不是:
git push -> main
而是:
git push -> Gerrit -> Code Review -> 审核通过 -> 才能合入
一些概念
change
Gerrit 不叫 commit,叫 Change
一个 Change 包含:
- 一次代码修改
- 多次修改版本(Patch Set)
Patch Set(补丁版本)
当你被 review 提意见后:
👉 你不是新建 commit,而是:
修改代码 → 重新提交 → 生成 Patch Set 2
👉 一个 Change 可以有:
Patch Set 1
Patch Set 2
Patch Set 3
Code Review 标签
常见有:
- +2:代码没问题(可以合入)
- +1:基本OK
- -1 / -2:不通过
还有:
- Verified(CI自动测试)
Submit(提交)
👉 满足条件后才能合入:
- 至少一个 +2
- CI 通过
- 无冲突
rebase cherrypick merge 有什么区别
👉 merge = 合并全部历史
👉 rebase = 把你的提交"挪到最新后面"
👉 cherry-pick = 只拿一个提交
假设现在:
master:
A---B---C---D
dev:
A---B---X---Y
merge(分支合并)
功能开发完成 → 合入主分支
git checkout dev
git merge master
结果
A---B---X---Y-------M
\ /
C---D---
✔ 把 master 的 所有提交(C、D)带过来
✔ 产生一个 merge commit(M)
✔ 历史是"分叉再汇合"
rebase(同步主线)
开发过程中,同步最新代码
假设现在
master:
A---B---C---D
dev:
A---B---X---Y
执行:
git checkout dev
git rebase master
结果
A---B---C---D---X'---Y'
- ✔ 不产生 merge commit
- ✔ 历史变成"直线"
- ✔ 你的提交被"重放"(变成 X'、Y')
一般的用法
git fetch origin
git rebase origin/dev
fetch做了什么
git fetch origin
从远程下载最新的代码,比如远程:
origin/dev:
A---B---C---D---E
更新到本低的远程分支记录
origin/dev → 指向 E
但是不会改当前的分支
假设本地是
dev:
A---B---C
origin/dev:
A---B---C---D---E
fetch之后
dev(你当前分支) ❌ 没变
origin/dev ✅ 更新了
那rebase是配合这个做什么:把我的代码,放到最新的 dev 后面
git fetch origin
git rebase origin/dev
fetch和pull
git fetch 用于从远程仓库获取最新代码并更新本地的远程分支引用
它不会修改当前工作分支
通常需要配合 rebase 或 merge 使用,将远程更新同步到本地分支
git pull 等价于
git fetch + git merge
自动合并
可能产生 merge commit
❗不受控(企业不喜欢)
git fetch 只同步远端的代码 不动当前的代码
cherry-pick
✔ 只复制一个 commit(D)
✔ 生成新 commit(D')
✔ 不带其他历史
git cherry-pick D
----------------------
A---B---X---Y---D'
常用的
👉 dev → release:
dev:新功能 + bug修复
release:只要 bug
👉 用:
git cherry-pick bug_commit
总结
原来的:
master:
A---B---C---D
dev:
A---B---X---Y
merge:
git checkout dev
git merge master
A---B---X---Y-------M
\ /
C---D---
rebase
git checkout dev
git rebase master
A---B---C---D---X'---Y'
cherry-pick
git cherry-pick D
----------------------
A---B---X---Y---D'
👉 同步用 rebase
👉 合并用 merge
👉 精确拿用 cherry-pick
- merge 用于合并两个分支,会保留完整历史并生成 merge commit
- rebase 用于将当前分支的提交移动到最新主线后,使提交历史更加线性
- cherry-pick 用于将某一个 commit 单独应用到当前分支
在实际开发中:
- 开发过程中使用 rebase 同步主线
- 合并分支通常由工具(如 Gerrit)自动完成
- bug 修复同步到其他分支时使用 cherry-pick
| 操作 | 本质 | 带什么 | 是否改历史 |
|---|---|---|---|
| merge | 合并分支 | 全部提交 | ❌ 不改 |
| rebase | 重排提交 | 你的提交 | ✔ 改 |
| cherry-pick | 复制提交 | 单个 commit | ✔ 新建 |
git reset
- - soft
git reset --soft HEAD~1
👉 做了什么:
- ✔ 回退 commit(HEAD 往回移)
- ❌ 不动暂存区
- ❌ 不动工作区
👉 状态:代码还在,已经 add 状态
- -mixed(默认模式)
git reset HEAD~1
👉 做了什么:
- ✔ 回退 commit
- ✔ 清空暂存区(unstage)
- ❌ 不动工作区
👉 状态:代码还在,但变成"未 add"
- - hard
git reset --hard HEAD~1
👉 做了什么:
- ✔ 回退 commit
- ✔ 清空暂存区
- ✔ 删除工作区改动
👉 状态:
❗代码直接没了(回到历史状态)
整体的框架流程
拉代码 → 新建分支 → 改代码 → commit → push到refs/for/* → review → 修改 → 合入
一些词
👉 打 patch = 用"补丁文件"把代码改动应用过去------把修改写成"修改说明文件",别人拿去应用
打 patch
把 commit 变成一个"文件",再应用到别的地方
1️⃣ 生成 patch(补丁文件)
git format-patch -1 D
👉 会生成:
0001-fix-bug.patch
2️⃣ 应用 patch
git apply 0001-fix-bug.patch
或:
git am 0001-fix-bug.patch
apply vs am
| 命令 | 特点 |
|---|---|
git apply |
只改代码,不生成 commit |
git am |
应用 patch + 生成 commit |
开发流程
🧩 第一步:克隆代码
git clone ssh://user@gerrit.xxx.com:29418/project
🧩 第二步:开发代码
git checkout -b feature_xxx
🧩 第三步:提交 commit(重点)
git commit
👉 commit message 必须规范,例如:
fix: 修复I2C驱动初始化问题
Change-Id: Ixxxxxxxxxxxx
⚠️ 注意:
👉 Change-Id 是 Gerrit 识别同一个 Change 的关键!(通常自动生成)
🧩 第四步:push 到 Gerrit(不是 main!)
git push origin HEAD:refs/for/master
👉 这一步是关键区别:
| 普通 Git | Gerrit |
|---|---|
| push 到 main | push 到 refs/for/master |
👉 含义:
-
不直接合入
-
进入 Review 流程
git push <远程> <本地>:<远程目标>
对应
git push origin HEAD:refs/for/master
具体
| 部分 | 含义 |
|---|---|
| origin | 远程仓库 |
| HEAD | 当前分支最新提交,当前分支的最新 commit |
| refs/for/master | Gerrit 的"审核入口" |
refs/for/master = "我要提交到 master,但先走审核流程",把代码提交到 master 的 review 队列里
把"当前最新提交" → 推送到 Gerrit 的 master 审核队列
你本地 commit
↓
git push origin HEAD:refs/for/master
↓
Gerrit 创建 Change
↓
Code Review
↓
通过后 → merge 到 master
还可以分组提交
refs/for/master%topic=xxx'
批量管理 Change
🧩 第五步:Code Review
同事会:
- 看代码
- 留 comment
- 打分
🧩 第六步:修改代码
git commit --amend
git push origin HEAD:refs/for/master
👉 会变成:
- Patch Set 2
🧩 第七步:审核通过 → 合入
👉 Gerrit 自动帮你 merge
多分支 + Gerrit + cherry-pick 实战案例
我们假设有 3 个分支:
master → 主线(开发主干)
dev → 日常开发
release → 已发布版本(稳定)
👉 你接到一个任务:修复 I2C 驱动 bug(dev 分支) 然后同步到 release 分支(但不能带其他功能)
完整实战流程
🧪 Step 0:准备环境(模拟)
git clone ssh://xxx@gerrit.company.com:29418/project
cd project
git checkout dev
🧪 Step 1:从 dev 拉分支开发
git checkout -b fix_i2c_bug
👉 当前结构:
dev:
A---B---C
你的分支:
A---B---C (fix_i2c_bug)
🧪 Step 2:修改代码
假设你改了:
// i2c_driver.c
init_i2c(); // 修复初始化问题
🧪 Step 3:提交(生成 Change)
git add .
git commit -m "fix: 修复I2C初始化失败问题"
🧪 Step 4:提交到 Gerrit(进入 review)
git push origin HEAD:refs/for/dev
👉 此时:
Gerrit:
Change 1001
└── Patch Set 1
以上总结一下:
# 1️⃣ 新建分支(你自己的开发空间)
git checkout -b fix_i2c_bug
# 2️⃣ 写代码
vim xxx.c
# 3️⃣ 本地提交(只是记录)
git add .
git commit -m "fix: xxx"
# 4️⃣ 提交到 Gerrit(关键步骤)
git push origin HEAD:refs/for/dev
😅 Step 5:被 reviewer 打回
reviewer 说:初始化顺序有问题
🧪 Step 6:修改代码
# 修改代码后
git commit --amend
git push origin HEAD:refs/for/dev
👉 变成:
Change 1001
├── Patch Set 1
└── Patch Set 2
🧪 Step 7:期间 dev 分支更新了(真实情况🔥)
别人提交了代码:
dev:
A---B---C---D---E
👉 你必须同步(否则提交会被拒)
✅ 正确操作:rebase
git fetch origin
git rebase origin/dev
👉 变成:
A---B---C---D---E---F(你的commit)
🧪 Step 8:再次提交(更新 Patch Set)
git push origin HEAD:refs/for/dev
👉 Gerrit:
Change 1001
├── Patch Set 1
├── Patch Set 2
└── Patch Set 3
🎉 Step 9:审核通过 → 自动合入
👉 dev 分支现在:
A---B---C---D---E---F(你的修复)
同步到 release
👉 现在你要把这个 bug 修复同步到 release
❗ 当前情况:
dev:
A---B---C---D---E---F(修复bug)
release:
A---B---C (稳定版本,没有新功能)
❌ 错误做法:
git checkout release
git merge dev ❌
👉 问题:
- D、E(新功能)也进来了 ❌
✅ 正确做法:cherry-pick
🧪 Step 10:切换到 release
git checkout release
🧪 Step 11:找到你的 commit
git log
找到:
F = fix: 修复I2C初始化失败问题
🧪 Step 12:cherry-pick
git cherry-pick F
👉 结果:
release:
A---B---C---F'
注意
- F' 是新的 commit(不是原来的 F)
- 只带 bug 修复
🧪 Step 13:提交到 Gerrit(release 分支)
git push origin HEAD:refs/for/release
👉 Gerrit:
Change 2001
└── Patch Set 1
🧪 Step 14:review → 合入 release
👉 最终:
release:
A---B---C---F'
整个流程总结(非常重要)
1. dev 分支开发 → 提交 Gerrit
2. review → amend → patch set
3. rebase 保持最新
4. 合入 dev
5. cherry-pick 到 release
6. 再走一轮 Gerrit
Gerrit Reviewer端基本命令
作为 Gerrit reviewer,主要通过
git fetch获取 patch set,本地使用git show和git diff查看改动,并通过编译运行验证功能。同时我会对比不同 patch set 的差异,确保问题被正确修复。评审时重点关注代码逻辑、性能、以及潜在的并发或内存问题,最终在 Gerrit 上给出 +1 或 +2 的评审意见。
你站在 reviewer 侧,本质做 4 件事:
- 拉代码(fetch patch)
- 查看改动(diff / log)
- 本地验证(编译 / 运行 / 测试)
- 给 review(+1 / -1 / +2 / 提意见)
掌握的 Gerrit 命令
1️⃣ 获取待评审代码
Gerrit 不用 git pull,而是用 fetch
标准命令
git fetch origin refs/changes/xx/12345/1
git checkout FETCH_HEAD
解释:
12345→ change number1→ patch set(第几版)
👉 你必须理解:
一个 change = 多个 patch set(版本)
2️⃣ 查看代码改动
看提交信息
git log -1
看改了什么
git show
看具体 diff
git diff HEAD~1
👉 实际中你更常用:
git show HEAD
3️⃣ 对比不同 patch set(很关键)
比如 reviewer 常见场景:
"作者改了第二版,我只想看改了啥"
做法:
git fetch origin refs/changes/xx/12345/1
git checkout -b ps1 FETCH_HEAD
git fetch origin refs/changes/xx/12345/2
git checkout -b ps2 FETCH_HEAD
git diff ps1 ps2
👉 这个是 reviewer 很加分的技能(很多人不会)
4️⃣ 本地测试代码
make
./run_test
👉 Reviewer 不只是看代码:
- 能不能编译
- 会不会崩
- 性能有没有问题
5️⃣ Cherry-pick 到当前分支
有时候你在自己分支验证:
git cherry-pick <commit-id>
👉 用于:
- 集成测试
- 和其他代码一起跑
6️⃣ 评审后操作(在 Gerrit Web 做,但你要懂)
虽然操作在网页,但你必须理解这些:
常见 Review 分值
+1:基本OK-1:有问题+2:可以合入(通常是高级 reviewer)
Verified(CI)
+1:测试通过-1:测试失败
Reviewer 必懂 Git 操作
这些不是 Gerrit 专属,但 reviewer 经常用:
1️⃣ rebase(看作者有没有处理冲突)
git rebase origin/master
你要看:
- 有没有冲突
- 提交是否干净
2️⃣ merge 测试
git merge origin/master
👉 用来检查:
合入主干会不会炸
3️⃣ 查看提交历史是否规范
git log --oneline --graph
你要看:
- 有没有乱七八糟的 commit
- 是否 squash 过
收到一个 Gerrit review
Step 1:拉代码
git fetch origin refs/changes/34/1234/2
git checkout FETCH_HEAD
Step 2:看改动
git show
Step 3:跑代码
make
./test
Step 4:检查问题
你关注:
- 逻辑是否正确
- 是否有 bug
- 性能问题
- 代码风格
Step 5:如果有问题
👉 在 Gerrit 上:
- comment
- 打
-1
Step 6:作者修改(Patch Set 3)
git fetch origin refs/changes/34/1234/3
git checkout FETCH_HEAD
👉 然后对比:
git diff ps2 ps3
Step 7:确认没问题
👉 打:
+2
总结(你必须掌握的最小集合)
如果只记最核心:
# 拉 patch
git fetch origin refs/changes/.../.../...
git checkout FETCH_HEAD
# 看改动
git show
# 对比 patch
git diff ps1 ps2
# 测试
make
# cherry-pick(可选)
git cherry-pick <commit>