为啥向安卓开源项目提交代码,非得用 refs/for/ 这种奇怪格式?一篇彻底搞懂 Gerrit 提交机制的实战指南
引言:从“普通 Git 推送”到“AOSP 提交”的困惑
如果你之前用过 GitHub、GitLab 这类平台,一定会对 git push origin main 这种简洁的推送命令非常熟悉——本地代码写完,add、commit 后一键推送,代码就直接合并到远程分支了。
但当你投身 AOSP(安卓开源项目) 或其他基于 Gerrit 的代码库时,突然发现:
git push aosp master # 直接推送?权限被拒!
取而代之的是这种“看不懂”的命令:
git push aosp master:refs/for/master
为什么必须加 refs/for/?直接推送不行吗?今天咱们就用最通俗的方式,彻底拆解背后的原理和实操逻辑!
一、核心差异:Gerrit 的“审核铁律”
普通 Git 平台(GitHub/GitLab):代码合并 = 信任开发者
你有仓库写权限时,push 就是“直接合并”,代码立刻生效(除非开了保护分支)。
Gerrit 平台(AOSP/LineageOS 等):代码合并 = 必须审核
Gerrit 是专为大型开源项目设计的代码托管系统,核心规则是:任何代码在合并前,必须经过至少 1 位 Reviewer(审核人)的批准。
为了强制执行这条规则,Gerrit “阉割”了直接推送的权限——你无法像普通 Git 那样,用 git push 直接修改远程分支的代码。
取而代之的是 refs/for/ 这个“审核投递口”:
- 推送格式:
git push <远程名> <本地分支>:refs/for/<目标分支> - 作用:把你的代码“投递”到审核队列,不会直接合并,而是生成一个“代码审核任务(Change)”,等 Reviewer 网页端审核通过后,才自动合并。
二、实战:为什么你必须用 refs/for/?
场景 1:普通 Git(GitHub)的“直推”逻辑
假设你在 GitHub 有一个仓库,远程名是 origin,本地分支是 main。
推送命令:
git push origin main
执行后:
- GitHub 直接把你的
main分支代码合并到远程main分支。 - 代码立刻生效,其他协作者拉取时,会直接获取你的新代码。
场景 2:Gerrit(AOSP)的“审核”逻辑
假设你在 AOSP 有一个远程仓库 aosp,本地分支是 master。
错误操作(直接推送):
git push aosp master
执行后大概率报错:
remote: error: denied: You are not allowed to push code directly to this branch.
原因:Gerrit 禁止直接推送 refs/heads/*(远程分支的存储路径),必须走审核流程。
正确操作(用 refs/for/ 投递审核):
git push aosp master:refs/for/master
执行后:
- Gerrit 拦截请求,把你的提交包装成一个 “Change(审核任务)”。
- 生成一个审核页面链接(如
http://gerrit.example.com/c/12345),你和 Reviewer 可以在网页端评论、打分。 - 只有审核通过(+2 分)并点击“Submit”后,代码才会真正合并到远程
master分支。
三、深入:refs/for/ 到底是什么?
1. 引用(Ref)的底层逻辑
Git 的分支本质上是 “引用(Ref)” —— 一个指向某次提交的指针。
- 普通分支:
refs/heads/main(本地分支) → 远程分支是refs/remotes/origin/main。 - Gerrit 的审核分支:
refs/for/main→ 这不是一个真正的“分支”,而是 Gerrit 定义的 “审核队列”。
2. 推送时的“隐秘逻辑”
当你执行:
git push aosp master:refs/for/master
Git 实际做的是:
- 把本地
master分支的提交,推送到远程的refs/for/master引用。 - Gerrit 检测到
refs/for/开头的引用,触发 “审核流程”:- 创建一个新的 Change(审核任务)。
- 把你的提交作为这个 Change 的“初始补丁集(Patch Set)”。
- 等待 Reviewer 处理。
四、实操:从“本地提交”到“Gerrit 审核”的完整流程
假设你已经完成了本地修改、add、commit,现在要把代码推送到 Gerrit 审核:
步骤 1:确认远程仓库名
先查看远程仓库配置:
git remote -v
输出示例:
aosp http://gerrit.example.com/platform/Customer.git (fetch)
aosp http://gerrit.example.com/platform/Customer.git (push)
这里的 aosp 就是远程名(对应你之前的 git push aosp ...)。
步骤 2:推送至 refs/for/
假设你的本地分支是 master,目标远程分支也是 master,推送命令为:
git push aosp master:refs/for/master
如果本地分支是 my-feature,目标远程分支是 feature-branch:
git push aosp my-feature:refs/for/feature-branch
步骤 3:处理推送结果
推送成功后,终端会输出类似内容:
remote: SUCCESS
remote: http://gerrit.example.com/c/12345 # 这是你的审核任务链接!
打开这个链接,你就能看到自己的代码审核页面,等待 Reviewer 批准即可。
五、常见问题 & 解决方案
1. 推送时提示“权限被拒”?
- 原因:你没有
aosp远程仓库的写权限。 - 解决:联系项目管理员,申请对应的推送权限(通常需要加入项目的“Contributors”组)。
2. 推送后看不到审核任务?
- 原因:可能推送的分支名错误(如
refs/for/xxx不存在)。 - 解决:检查目标分支是否存在(可询问同事或查看仓库分支列表),确保
refs/for/后的分支名与远程一致。
3. 想修改已推送的代码?
Gerrit 的设计是 “审核未通过时,可更新补丁集”:
- 本地修改代码,
add、commit --amend(修改上次提交)。 - 重新推送:
git push aosp master:refs/for/master。 - Gerrit 会自动把新提交作为 “新的补丁集(Patch Set)”,附加到原来的审核任务下。
六、总结:Gerrit 的“审核思维”
用一句话概括:Gerrit 的 refs/for/ 是“审核流程”的入口,直接推送是“绕过审核”的违规操作。
记住这个核心逻辑,你就能理解所有基于 Gerrit 的项目(如 AOSP、LineageOS、CyanogenMod 等)的提交规则。
下次再遇到“为什么必须加 refs/for/”,你可以自信地回答:因为代码世界里,“审核”是质量的护城河,而 refs/for/ 是通往护城河的唯一桥梁。
延伸阅读
希望这篇指南能帮你彻底搞懂 Gerrit 的提交逻辑!如果觉得有用,欢迎分享给更多被“refs/for/”困扰的开发者~
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)