Git + Gerrit 第六课:commit --amend、Patch Set 与 Change-Id

本节目标

这一节开始进入 Gerrit 工作流的核心。

你要理解这些问题:

复制代码
什么是 git commit --amend?
为什么 Gerrit 修改评审意见时经常用 amend?
什么是 Change?
什么是 Patch Set?
什么是 Change-Id?
为什么 Change-Id 不能随便改?
如何更新同一个 Gerrit Change,而不是创建新的 Change?

本节重点命令:

复制代码
git commit --amend
git log --oneline
git log -1
git push origin HEAD:refs/for/master
git push origin HEAD:refs/for/develop

1. 先理解一个真实工作场景

假设你在公司开发一个登录功能。

你完成代码后提交:

复制代码
git add .
git commit -m "实现用户登录功能"
git push origin HEAD:refs/for/master

Gerrit 上生成了一个代码评审页面。

评审者看完后评论:

复制代码
1. 用户名为空时需要提示错误信息。
2. 密码校验逻辑建议拆成独立方法。
3. 这个变量名不够清楚,请改一下。

这时你要修改代码。

新手容易这样做:

复制代码
git add .
git commit -m "修改 review 问题"
git push origin HEAD:refs/for/master

这样可能会创建一个新的提交,甚至在 Gerrit 上生成一个新的 Change。

但 Gerrit 常见期望是:

复制代码
在原来的 Change 上生成新的 Patch Set。

所以更常见的做法是:

复制代码
git add .
git commit --amend
git push origin HEAD:refs/for/master

2. git commit --amend 是什么

amend 的意思是:

复制代码
修正,修改,补充。

所以:

复制代码
git commit --amend

意思是:

复制代码
修改上一次提交。

它不是创建一个普通的新提交,而是用一个新的提交替换上一个提交。

原来历史可能是:

复制代码
A --- B --- C

你在 C 的基础上修改代码,然后执行:

复制代码
git add .
git commit --amend

历史会变成:

复制代码
A --- B --- C'

注意:

复制代码
C 被 C' 替换了。
C' 是一个新的 commit id。

也就是说:

复制代码
amend 会重写最近一次提交。

3. amend 和普通 commit 的区别

普通提交:

复制代码
git commit -m "修复 review 问题"

会在原提交后面新增一个提交:

复制代码
A --- B --- C --- D

amend

复制代码
git commit --amend

会修改最近一次提交:

复制代码
A --- B --- C'

简单记忆:

复制代码
普通 commit:新增一次提交。
commit --amend:修改上一次提交。

4. 为什么 Gerrit 常用 amend

Gerrit 的核心单位是 Change

一个 Change 表示:

复制代码
一次待评审的代码变更。

评审者通常希望一个 Change 表达一件清楚的事情,例如:

复制代码
实现用户登录功能
修复订单金额计算错误
增加配置文件读取逻辑

如果评审者提出意见,你修改后不应该再创建很多零散提交:

复制代码
实现用户登录功能
修改 review 问题
继续修改
再改一次
修复拼写

这种历史会让评审很难看。

更好的方式是:

复制代码
同一个 Change,不断生成新的 Patch Set。

例如:

复制代码
Change 12345:实现用户登录功能
  Patch Set 1:第一次提交
  Patch Set 2:根据评审意见修改
  Patch Set 3:修复 CI 问题
  Patch Set 4:再次调整变量名

这样 Gerrit 页面会很清楚:

复制代码
这是同一个代码变更,只是经过了多轮修改。

5. Change 是什么

在 Gerrit 中,Change 可以理解为:

复制代码
一个代码评审单。

你推送一次待评审代码:

复制代码
git push origin HEAD:refs/for/master

Gerrit 会创建一个 Change。

这个 Change 里面包含:

  • 标题

  • 描述

  • 目标分支

  • 代码差异

  • 评审评论

  • Patch Set

  • CI 检查结果

  • Code Review 分数

  • Verified 分数

你可以把 Change 理解成:

复制代码
这次代码修改的评审页面。

6. Patch Set 是什么

Patch Set 是 Change 里的版本。

一个 Change 可以有多个 Patch Set。

例如:

复制代码
Change:实现用户登录功能

Patch Set 1:第一次提交
Patch Set 2:修复评审意见
Patch Set 3:修复单元测试
Patch Set 4:调整提交说明

Patch Set 的作用是:

复制代码
记录这个 Change 每一轮修改。

评审者可以比较:

复制代码
Patch Set 1 和 Patch Set 2 差异是什么?
Patch Set 2 和 Patch Set 3 又改了什么?

所以 Gerrit 很适合多人反复评审。

7. Change-Id 是什么

Gerrit 通常要求 commit message 里有一行:

复制代码
Change-Id: Ixxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

例如:

复制代码
实现用户登录功能

Change-Id: Iabc1234567890abcdef1234567890abcdef1234

Change-Id 的作用是:

复制代码
帮助 Gerrit 判断这次推送属于哪个 Change。

如果你修改代码后再次推送,只要:

复制代码
Change-Id 没变
目标分支相同
仓库相同

Gerrit 通常就会把它识别为:

复制代码
同一个 Change 的新 Patch Set。

如果 Change-Id 变了,Gerrit 可能会认为:

复制代码
这是一个新的 Change。

8. Change-Id 从哪里来

大多数 Gerrit 项目会要求安装 commit-msg hook。

这个 hook 会在你提交时自动在 commit message 里追加:

复制代码
Change-Id: I...

如果没有这个 hook,你推送到 Gerrit 时可能会失败,并看到类似提示:

复制代码
missing Change-Id in message footer

意思是:

复制代码
提交信息中缺少 Change-Id。

不同公司安装 hook 的命令可能不同,常见形式类似:

复制代码
scp -p -P 29418 username@gerrit.example.com:hooks/commit-msg .git/hooks/

或者:

复制代码
curl -o .git/hooks/commit-msg https://gerrit.example.com/tools/hooks/commit-msg
chmod +x .git/hooks/commit-msg

在 Windows 上,具体命令要看公司 Gerrit 平台说明。

9. 第一次提交到 Gerrit 的流程

假设你已经在功能分支:

复制代码
git switch -c feature/login

修改代码后:

复制代码
git status
git diff
git add .
git diff --cached
git commit -m "实现用户登录功能"

查看最近一次提交:

复制代码
git log -1

确认 commit message 中有:

复制代码
Change-Id: I...

然后推送到 Gerrit:

复制代码
git push origin HEAD:refs/for/master

如果目标分支是 develop

复制代码
git push origin HEAD:refs/for/develop

10. 根据评审意见更新同一个 Change

评审者提出意见后,你修改代码。

然后执行:

复制代码
git status
git diff
git add .
git diff --cached
git commit --amend
git push origin HEAD:refs/for/master

如果目标分支是 develop

复制代码
git push origin HEAD:refs/for/develop

关键点:

复制代码
不要删除 Change-Id。
不要随便改 Change-Id。

这样 Gerrit 通常会生成:

复制代码
Patch Set 2

而不是创建一个新的 Change。

11. amend 时会打开编辑器怎么办

执行:

复制代码
git commit --amend

Git 可能会打开一个编辑器,让你修改提交信息。

如果提交标题不需要变,直接保存退出即可。

如果你想同时修改提交信息,可以在编辑器里改。

提交信息通常长这样:

复制代码
实现用户登录功能

补充用户名为空时的错误提示,并拆分密码校验逻辑。

Change-Id: Iabc1234567890abcdef1234567890abcdef1234

注意:

复制代码
Change-Id 那一行要保留。

12. 不打开编辑器的 amend

如果你只想把代码修改合入上一次提交,不想修改提交信息,可以使用:

复制代码
git commit --amend --no-edit

意思是:

复制代码
修改上一次提交,但保留原来的 commit message。

这是 Gerrit 中非常常用的命令。

常见流程:

复制代码
git add .
git commit --amend --no-edit
git push origin HEAD:refs/for/master

13. amend 会改变 commit id

即使你使用:

复制代码
git commit --amend --no-edit

commit id 也会变化。

因为提交内容变了。

原来可能是:

复制代码
abc1234 实现用户登录功能

amend 后可能变成:

复制代码
def5678 实现用户登录功能

这很正常。

Gerrit 不主要依靠 commit id 判断是否是同一个 Change。

Gerrit 主要依靠:

复制代码
Change-Id

14. amend 前后如何检查

amend 前:

复制代码
git status
git diff

加入暂存区:

复制代码
git add .

检查即将 amend 的内容:

复制代码
git diff --cached

执行 amend:

复制代码
git commit --amend --no-edit

查看最近一次提交:

复制代码
git log -1

确认:

复制代码
提交标题正确
Change-Id 还在
修改内容正确

15. amend 和 rebase 的关系

第五课学过 rebase

在 Gerrit 中,rebaseamend 经常一起出现。

15.1 只修改评审意见

如果只是根据评审意见修改代码:

复制代码
git add .
git commit --amend --no-edit
git push origin HEAD:refs/for/master

15.2 目标分支更新了

如果 Gerrit 提示你的 Change 无法自动合入,可能需要先同步目标分支:

复制代码
git fetch origin
git rebase origin/master
git push origin HEAD:refs/for/master

15.3 同时修改评审意见并同步主分支

一种常见流程:

复制代码
git fetch origin
git rebase origin/master

# 修改评审意见

git add .
git commit --amend --no-edit
git push origin HEAD:refs/for/master

如果 rebase 过程中有冲突:

复制代码
git status
# 解决冲突
git add 冲突文件
git rebase --continue

16. 一个 Change 对应一个 commit 的常见流程

很多 Gerrit 团队希望:

复制代码
一个 Change 对应一个 commit。

所以开发一个小功能时,推荐这样:

复制代码
git switch -c feature/login

# 修改代码

git add .
git commit -m "实现用户登录功能"
git push origin HEAD:refs/for/master

评审后继续:

复制代码
# 修改代码
git add .
git commit --amend --no-edit
git push origin HEAD:refs/for/master

多轮评审也一样:

复制代码
git add .
git commit --amend --no-edit
git push origin HEAD:refs/for/master

Gerrit 上会显示:

复制代码
Patch Set 1
Patch Set 2
Patch Set 3

17. 如果误创建了新的 Change

新手常见问题:

复制代码
明明只是修改评审意见,结果 Gerrit 上生成了一个新的 Change。

常见原因:

  • 新提交没有保留原来的 Change-Id

  • 使用普通 commit 创建了新提交

  • 手动改了 Change-Id

  • 推送到了不同目标分支

  • 本地分支历史整理错误

处理方式要看团队规范。

一般思路是:

复制代码
找到原 Change 的 Change-Id。
把本地提交信息改回正确的 Change-Id。
重新推送到 refs/for/目标分支。
关闭或 abandon 错误创建的新 Change。

具体操作可能涉及:

复制代码
git commit --amend

修改 commit message 中的 Change-Id

但新手遇到这种情况时,建议先问导师或团队同事,不要乱推。

18. amend 的风险

amend 会重写最近一次提交。

所以要注意:

复制代码
只 amend 自己负责的提交。
不要随便 amend 公共分支上的提交。
不要在多人共享分支上随意 amend 后强推。

在 Gerrit 工作流中,amend 自己的待评审 Change 是正常操作。

但在普通共享分支上,amend 已经被别人使用的提交可能会造成麻烦。

简单记忆:

复制代码
自己的本地提交可以 amend。
已经共享给别人依赖的历史不要随便 amend。

19. 实战练习:amend 修改上一次提交

创建练习仓库:

复制代码
mkdir git-amend-demo
cd git-amend-demo
git init

创建第一个文件:

复制代码
echo "login feature" > login.txt
git add login.txt
git commit -m "实现用户登录功能"

查看历史:

复制代码
git log --oneline

现在发现还需要补充一行:

复制代码
echo "empty username validation" >> login.txt

不要创建新提交,而是 amend:

复制代码
git add login.txt
git commit --amend --no-edit

再次查看历史:

复制代码
git log --oneline

你会发现:

复制代码
还是只有一个提交,但 commit id 变了。

20. 实战练习:修改提交信息

如果你发现提交信息写得不好:

复制代码
update

可以执行:

复制代码
git commit --amend

把提交信息改成:

复制代码
实现用户登录功能

如果是 Gerrit 提交,记得保留:

复制代码
Change-Id: I...

21. 实战练习:模拟 Gerrit Patch Set 思路

虽然本地没有真正的 Gerrit 页面,但可以模拟这个过程。

第一次提交:

复制代码
echo "version 1" > feature.txt
git add feature.txt
git commit -m "实现示例功能"

查看提交:

复制代码
git log --oneline

模拟 Review 意见,修改文件:

复制代码
echo "review fix" >> feature.txt
git add feature.txt
git commit --amend --no-edit

再次查看:

复制代码
git log --oneline

你会看到:

复制代码
仍然是一个提交,但提交内容已经更新。

这就类似 Gerrit 中:

复制代码
Patch Set 1 -> Patch Set 2

22. 推荐的 Gerrit 提交检查流程

第一次推送前:

复制代码
git status
git diff
git add .
git diff --cached
git commit -m "清楚描述本次修改"
git log -1
git push origin HEAD:refs/for/master

根据评审意见更新:

复制代码
git status
git diff
git add .
git diff --cached
git commit --amend --no-edit
git log -1
git push origin HEAD:refs/for/master

如果目标分支是 develop

复制代码
git push origin HEAD:refs/for/develop

23. 常见错误

错误一:Review 修改后使用普通 commit

错误做法:

复制代码
git commit -m "修改 review 问题"

更常见做法:

复制代码
git commit --amend --no-edit

错误二:删除 Change-Id

不要删除:

复制代码
Change-Id: I...

否则 Gerrit 可能无法识别同一个 Change。

错误三:手动乱改 Change-Id

不要随便改:

复制代码
Change-Id: Iabc...

除非你明确知道自己在修复错误的 Gerrit 关联关系。

错误四:amend 后忘记重新 push

本地 amend 后,Gerrit 不会自动更新。

你还需要:

复制代码
git push origin HEAD:refs/for/master

错误五:以为 amend 不会改 commit id

amend 会生成新的 commit id。

这是正常的。

Gerrit 主要看 Change-Id

24. 本节必须记住的命令

复制代码
git commit --amend
git commit --amend --no-edit
git log -1
git push origin HEAD:refs/for/master
git push origin HEAD:refs/for/develop

对应含义:

复制代码
git commit --amend                  修改上一次提交
git commit --amend --no-edit        修改上一次提交但不改提交信息
git log -1                          查看最近一次提交详情
git push origin HEAD:refs/for/master 推送到 Gerrit,申请合入 master
git push origin HEAD:refs/for/develop 推送到 Gerrit,申请合入 develop

25. 本节总结

这一节你学习了 Gerrit 工作流中的核心能力:

  • git commit --amend 用来修改上一次提交

  • Gerrit 中评审修改通常用 amend 更新同一个 Change

  • Change 是一次代码评审

  • Patch Set 是同一个 Change 的不同版本

  • Change-Id 用来让 Gerrit 识别同一个 Change

  • 修改评审意见后要保留 Change-Id

  • amend 后 commit id 会变化,这是正常的

  • amend 后还需要重新推送到 refs/for/目标分支

最重要的一句话:

复制代码
Gerrit 中更新评审意见,通常是 amend 后重新 push,从而生成新的 Patch Set。

下一节建议学习:

复制代码
Git stash:如何临时保存工作区修改,以及切换分支前如何保护未完成代码。
相关推荐
AIMath~18 小时前
向github中上传文件过大超过50M怎么办
网络·git·github
AIMath~1 天前
如何将一个新的文件夹使用git 工具提交到github新仓库中
git·github
满天星83035771 天前
【Git】原理及使用(二) (版本回退)
linux·git
愿天垂怜1 天前
【C++脚手架】ffmpeg 库的介绍与使用
linux·服务器·开发语言·c++·ide·git·ffmpeg
月夜的风吹雨1 天前
Linux 基础开发工具详解:从 yum 到 gdb 实战指南
linux·git·ubuntu·centos·vim
好运yoo1 天前
git cherry-pick
git
不是光头 强1 天前
Obsidian Git 插件安装与配置完全指南
git
.千余1 天前
【C++】C++核心语法:函数重载与缺省参数原理与避坑
c语言·开发语言·c++·经验分享·笔记·git·学习
meowrain1 天前
Git HTTPS Token 凭据配置指南
git·网络协议·https