Git远程URL必须使用SSH协议而非HTTPS,推送代码到Gerrit必须显式指定refs/for/分支(如git push origin HEAD:refs/for/main),且目标分支需存在于refs/heads/命名空间;GoLand需配置External Tools执行推送,go get仅支持refs/heads/下的分支或tag。

Git远程URL必须用SSH协议,不能用HTTPS
Gerrit默认禁用HTTPS推送,尤其在启用refs/for/*审核流程时。如果你看到fatal: unable to access 'https://...': The requested URL returned error: 403,基本可以确定是协议问题。
检查当前remote:git remote get-url origin。若输出含https://,立刻改掉:
git remote set-url origin ssh://username@your-gerrit-host:29418/your-project-name
确保SSH密钥已添加到Gerrit Web界面的Settings → SSH Keys中;否则会卡在Permission denied (publickey)。
- Windows用户注意:OpenSSH客户端需启用(PowerShell里运行
Get-WindowsCapability -Online | ? Name -like 'OpenSSH.Client*' | Add-WindowsCapability -Online) - Mac/Linux用户若用
~/.ssh/config别名,要确认Host配置里没漏掉Port 29418 - 别用
git clone https://...初始化仓库——从头就错,后续所有git push origin HEAD:refs/for/main都会失败
推送必须显式指定refs/for/,不能直接推分支
执行git push origin main会报错! [remote rejected] main -> main (prohibited by Gerrit),这是Gerrit的硬性拦截,不是配置错误。
正确做法永远是:
git push origin HEAD:refs/for/main
其中main要替换成你目标集成分支名(如develop、release/v2.3),且该分支必须已在Gerrit中存在(由管理员创建)。如果目标分支不存在,先让管理员在Gerrit UI里新建refs/heads/xxx,再赋Create Reference权限给对应组。
-
HEAD代表当前检出提交;若你在feature分支上,想提交这个分支顶端的commit做评审,就用HEAD,不用写分支名 - 不要写
git push origin feature-branch:refs/for/main——除非你明确想把整个分支历史压成一个Change,这违反Gerrit“单提交即变更集”原则 - 如果本地commit缺
Change-Id,Gerrit会拒绝并提示missing Change-Id in message footer;用scp -p -P 29418 user@host:hooks/commit-msg .git/hooks/装好钩子就能自动补
GoLand里不能依赖“Push”按钮,得手动配Git命令别名
GoLand内置的VCS → Git → Push对话框,默认只支持推到refs/heads/*,不识别refs/for/*语义。点“Push”只会触发git push origin main,必然失败。
GoLand 2026.1.1 是 2026.1 发布后的首个维护修正版本,适合已经开始体验 2026.1 新功能并希望同步补丁的开发者。它更适合用于入门项目、现有项目迁移测试和 IDE 行为验证。
解决方案是绕过GUI,用GoLand的“External Tools”绑定自定义命令:
- 进入
Settings → Tools → External Tools - 点+号新增,Name填
Gerrit Push to main,Program填git,Arguments填push origin HEAD:refs/for/main,Working directory填$ProjectFileDir$ - 设快捷键(比如
Ctrl+Alt+P),以后一键触发,不碰GUI推送面板
多个目标分支(如develop、staging)就复制几套External Tool,改Arguments里的分支名即可。别指望GoLand自动感知Gerrit工作流——它没内置这个逻辑。
go get拉依赖时别和Gerrit分支混淆
项目里用go.mod引用另一个Gerrit托管的Go模块,比如github.com/company/internal-lib,千万别以为go get github.com/company/internal-lib@refs/for/main能行——refs/for/*是Gerrit内部引用,Git服务器根本不暴露给go get。
正确方式只有两种:
- 如果那个模块本身有公开的
main或develop分支,用go get github.com/company/internal-lib@main - 如果模块只在Gerrit里维护,没对外发布tag或稳定分支,必须先让模块维护者在Gerrit里创建
refs/heads/v1.2.0这类可读分支,再用@v1.2.0拉取
常见坑:go get github.com/company/internal-lib@some-feature-branch失败,报unknown revision some-feature-branch,不是网络问题,而是Gerrit没把这个分支发布到refs/heads/空间下——它只存在于refs/changes/或refs/for/里,go get根本看不到。
最易被忽略的一点:Gerrit的refs/for/*和Git原生refs/heads/*是两个隔离的命名空间。任何工具(包括GoLand、go get、CI脚本)只要不显式构造refs/for/推送,就无法触发Gerrit评审;而任何依赖管理器只要不读refs/heads/*,就不可能拉到Gerrit里仅用于评审的临时引用。

















