Featured image of post GitHub 的 Verified 提交、SSH Key 与 noreply 隐私邮箱,一次讲清楚

GitHub 的 Verified 提交、SSH Key 与 noreply 隐私邮箱,一次讲清楚

用通俗方式讲清 GitHub 的 Verified、SSH Key 和 noreply 隐私邮箱分别是做什么的,以及 GitHub 与 GitLab 怎么配置才不容易互相影响。

-- 次浏览
-- 条评论

很多人第一次配 GitHub 提交签名时,都会被几个词绕晕:邮箱验证noreply 匿名邮箱SSH keyVerified,再加上一个经典问题:GitHub 和 GitLab 会不会互相影响

它们看起来都和“提交身份”有关,但其实管的是不同的事。

这篇文章不聊花哨配置,只想把 4 个最常见的问题说清楚:

  • Verified 到底是靠什么出现的
  • auth keysign key 分别管什么
  • noreply 到底能不能直接让提交变成 Verified
  • 本地同时操作 GitHub 和 GitLab 时应该怎么配

写在前面

如果你只想先记住一句话,可以先看这 4 句:

  • noreply 解决的是“提交里显示哪个邮箱”。
  • Verified 解决的是“这个提交有没有被数字签名验证通过”。
  • auth key 解决的是“你能不能通过 SSH 连上 GitHub 并 push 代码”。
  • sign key 解决的是“GitHub 会不会把这次 commit 标记成 Verified”。

这几件事彼此有关,但不是一回事。大多数人踩坑,不是因为命令不会敲,而是一开始就把目标搞混了。

如果想更快建立整体判断,可以先看这张对照表:

你想解决的问题主要看什么会不会直接影响 Verified会不会影响邮箱是否暴露
让提交显示 Verified是否开启提交签名,公钥是否作为 Signing Key 添加到账户不直接决定
git push / git pull 走 SSHSSH 认证 key 是否可用不会不会
不暴露真实邮箱user.email 是否改成 noreply不会直接决定
避免 GitHub 和 GitLab 配置互相污染全局配置和仓库本地配置怎么划分间接影响排查效率

先分清三个最容易混淆的概念

1. 账号邮箱验证

这是 GitHub 账号层面的基础设置,说白了就是让 GitHub 确认“这个邮箱确实是你的”。

它主要解决的是账号通知、找回、身份归属这些问题。

但是它不会让你的提交自动显示 Verified

2. 提交显示 Verified

这指的是“这次提交有没有经过数字签名验证”。

GitHub 会检查这次 commit 是否带有有效签名。当前支持 GPGSSHS/MIME 三种方式。对大多数个人用户来说,SSH 往往是最省事的一种。

也就是说,Verified 不是看你用了什么邮箱,而是看你有没有对提交做签名,以及 GitHub 能不能验证这个签名。

3. noreply 隐私邮箱

这是 GitHub 提供的一种匿名邮箱,用来避免你在 commit 里直接暴露真实邮箱。它常见的格式如下:

1
ID+USERNAME@users.noreply.github.com

它的作用是隐藏真实邮箱,同时让 GitHub 仍然可以把提交归属到你的账号和贡献图。

但它本身不会让 commit 变成 Verified


auth keysign key 到底分别做什么

把这两个概念分清楚,后面的设置页面就不会那么绕。

auth key:证明“你能操作仓库”

auth key 用在 SSH 连接阶段,也就是你和 GitHub “建立连接”的时候,比如:

1
2
3
4
git clone git@github.com:owner/repo.git
git fetch
git pull
git push

当你执行这些命令时,GitHub 需要确认两件事:

  • 你是不是这个账号的人
  • 你有没有权限访问这个仓库

所以 auth key 的作用很直接:

  • 让你能通过 SSH 连接 GitHub
  • 让你能 clone、fetch、pull、push

如果没有它,SSH 方式下通常连 push 都过不去。

sign key:证明“这次提交确实是你签的”

sign key 用在 git commit 阶段。它不是拿来“登录 GitHub”的,而是给 commit 内容附带一个数字签名。

当你执行:

1
git commit -S -m "feat: add signed commit"

或者开启自动签名:

1
git config commit.gpgsign true

Git 会在 commit 里写入一段签名信息。GitHub 收到这个 commit 后,会检查:

  • 签名是否有效
  • 对应公钥是否已添加到你的 GitHub 账号
  • 这把公钥是否被登记为 Signing Key

都通过了,GitHub 才会显示 Verified

这里有个很容易误会的点。

user.email 会影响提交归属、贡献图统计,以及你有没有暴露真实邮箱;但不要把它直接理解成“SSH 签名能不能显示 Verified 的唯一前提”。对 SSH signing 来说,核心仍然是签名本身能否被你账号里的 Signing Key 验证通过。

一个比喻就够了

  • auth key 像门禁卡,决定你能不能进大楼
  • sign key 像签字章,决定这份文件能不能证明是你签的

两者可以是同一把钥匙材料,但职责不同。


为什么同一把 SSH key 可以同时用于 authsign

这也是很多人第一次配置时最容易卡住的地方。

答案其实不复杂:同一把 key 可以同时承担认证和签名两种用途,但 GitHub 会把这两种用途分开记录。

比如你本地有这一对 key:

  • 私钥:~/.ssh/id_ed25519
  • 公钥:~/.ssh/id_ed25519.pub

你完全可以只维护这一对密钥,然后在 GitHub 的 Settings -> SSH and GPG keys 页面里按用途决定怎么登记:

  1. 如果要让提交显示 Verified,把公钥添加为 Signing Key
  2. 如果还要用同一把 key 走 SSH clone、pull、push,再额外把它添加为 Authentication Key

注意,这不是要求你生成两把不同的 key。重点只是 GitHub 会把“认证用途”和“签名用途”分开记录。

所以:

  • 同一把 key 可以同时给 git push 做 SSH 认证
  • 同一把 key 也可以给 git commit 做 SSH 签名
  • 但如果你只关心 Verified,先配 Signing Key 就够了

想让每次 GitHub 新提交都显示 Verified,最推荐怎么配

如果你主要是个人开发者,当前最省事的做法通常就是 SSH commit signing

第一步:确认 Git 版本

GitHub 官方说明,SSH signature verification 需要 Git 2.34 或更高版本。

1
git --version

第二步:确认本机是否已有 SSH key

1
ls -al ~/.ssh

如果你已经有 id_ed25519id_ed25519.pub,大多数情况下可以直接复用。

如果没有,可以生成一把新的:

1
ssh-keygen -t ed25519 -C "你的GitHub邮箱"

第三步:先添加 Signing Key,需要 SSH 传输时再补 Authentication Key

进入 GitHub:

Settings -> SSH and GPG keys

如果你的目标只是让提交显示 Verified,关键动作是:

  • 一次作为 Signing Key

如果你还想继续用这把 key 走 SSH 方式 clone、pull、push,再额外添加一次:

  • 一次作为 Authentication Key

也就是说:

  • Verified 主要取决于 Signing Key
  • Authentication Key 只负责 SSH 传输认证
  • 两者可以是同一把 key,但不是必须为了 Verified 同时都配上

第四步:告诉 Git 以后用这把 key 给提交签名

如果你想让当前仓库自动签名:

1
2
3
git config gpg.format ssh
git config user.signingkey ~/.ssh/id_ed25519.pub
git config commit.gpgsign true

如果你希望所有仓库都默认启用签名,可以把上面的命令都加上 --global

但如果你同时还在用 GitLab,而且不想让 GitLab 仓库默认签名,我更建议只在 GitHub 仓库里做本地配置,不要一开始就全局打开。

第五步:确认提交邮箱配置正确

这一点很容易被忽略。即使签名没问题,如果 user.email 配置得很混乱,后续在排查贡献归属、邮箱暴露和多平台配置时会非常烦。

先看当前仓库实际使用的邮箱:

1
git config user.email

如果你希望隐藏真实邮箱,可以在 GitHub 仓库里设置成自己的 noreply 地址:

1
git config user.email "你的GitHub-noreply邮箱"

更直白一点说:

  • user.email 主要决定提交里写入哪个邮箱
  • 它影响隐私暴露和账号归属
  • 但不要把它直接等同于“SSH 签名能不能生效”

第六步:做一次测试提交

1
2
git commit -m "test signed commit"
git push

如果前面的签名配置都已生效,这次新提交推到 GitHub 后,通常就会显示 Verified

补充:为什么网页上直接改文件,也可能显示 Verified

这个问题也很常见。

如果你是在 GitHub 网页端直接编辑文件、合并某些 PR,或者通过 GitHub 提供的受支持界面生成提交,这类提交可能会由 GitHub 代表平台自动签名。 所以即使你本地没配 SSH signing,页面上仍然可能看到 Verified

这和“你在本地命令行里如何配置签名”不是一回事,别把两者混在一起。


同时使用 GitHub 和 GitLab,应该怎么配才不互相干扰

这是实际使用里比“按钮怎么点”更重要的问题。

很多人的真实场景不是“我只用 GitHub”,而是:

  • 一部分仓库推到 GitHub
  • 一部分仓库推到 GitLab
  • GitHub 想要 Verified
  • GitLab 不一定想开启签名验证

这种情况下,最稳妥的做法不是一上来就全局把所有东西都打开,而是把“你具备签名能力”和“哪些仓库默认启用签名”分开。

推荐方案:只在 GitHub 仓库开启自动签名

全局只保留基础能力:

1
2
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub

GitHub 仓库里单独开启:

1
2
git config commit.gpgsign true
git config user.email "你的GitHub-noreply邮箱"

GitLab 仓库里保持普通配置,或者显式关闭:

1
2
git config commit.gpgsign false
git config user.email "你的GitLab邮箱"

这样配置的好处很直接:

  • GitHub 仓库会自动签名,提交更容易显示 Verified
  • GitLab 仓库不会被你无意中全局签名
  • 两个平台的邮箱也能分开管理

如果你接受所有仓库都默认签名

那也可以直接全局开启:

1
2
3
git config --global gpg.format ssh
git config --global user.signingkey ~/.ssh/id_ed25519.pub
git config --global commit.gpgsign true

这样通常不会影响 GitLab 的正常 push。只是 GitLab 那边如果没有配置对应的签名 key,页面未必会显示它自己的验证状态。

最后一定要会看实际生效配置

这条命令非常实用:

1
git config --list --show-origin

它能直接告诉你当前仓库到底是哪里把 user.emailcommit.gpgsignuser.signingkey 这些值设上的。很多“为什么和我想的不一样”的问题,都是靠这条命令排查出来的。


noreply 隐私邮箱到底解决什么问题

它只解决一个问题:避免在 commit 里公开暴露真实邮箱

如果你不想把真实邮箱直接写进 Git 历史里,就可以把 GitHub 仓库的提交邮箱改成 GitHub 提供的匿名地址。

它不会替你完成签名

这一点最容易被误会。

  • 用真实邮箱但不签名,不会有 Verified
  • noreply 但不签名,也不会有 Verified
  • 只有签名通过了,才会显示 Verified

所以最理想的组合通常是:

  • 提交邮箱用 noreply
  • 提交本身用 SSHGPG 签名

也就是同时兼顾“匿名”和“已验证”。

它在网页端和命令行端的行为不一样

如果你在 GitHub 账号设置里开启了:

  • Keep my email addresses private

那么 GitHub 网页端产生的提交会优先使用 noreply

但如果你在本地命令行里提交,GitHub 不会自动改写你的 user.email。真正生效的仍然是你本地 Git 配置。

也就是说,如果你本地还是:

1
git config user.email "you@company.com"

那你从命令行提交出去的 commit,依然会带着这个真实邮箱。

这个设置建议一起打开

如果你很在意邮箱泄露,建议在 GitHub 的 Settings -> Emails 中一并开启:

  • Keep my email addresses private
  • Block command line pushes that expose my email

第二个选项的意义是:如果你从命令行 push 了会暴露私人邮箱的提交,GitHub 可以直接阻止这次 push,避免你事后才发现配置配错了。


开启 noreply 之后,旧 commit 会不会自动变匿名

不会。

这件事没有灰度空间,结论就是:历史提交不会因为你后来改了邮箱策略而自动重写

原因也不复杂。Git 的 commit 对象里本来就记录了当时的作者和提交者信息。只要那次提交已经生成,它的邮箱元数据也就固定了。

所以:

  • 旧 commit 当时如果用的是真实邮箱,历史里还是那个真实邮箱
  • 你后来开启 Keep my email addresses private,只会影响之后的新提交
  • GitHub 不会替你重写仓库历史

如果仓库已经公开,工程上就应该默认认为这些旧邮箱已经跟着 Git 历史一起公开过了。


如果想把旧 commit 也改成匿名邮箱,要付出什么代价

真正有效的方法只有一个:重写 Git 历史

常见做法是用 git-filter-repo 之类的工具,把旧提交里的 author 或 committer email 批量替换掉,然后再强制推送。

但这件事的代价不小:

  • 所有受影响 commit 的 hash 都会变化
  • 依赖这些历史的分支、标签、PR 引用都会受到影响
  • 协作者本地仓库需要重新同步,严重时甚至要重新 clone
  • 如果仓库已经被 fork、镜像或拉取,旧历史也不一定能彻底消失

所以大多数情况下,更现实的做法是:

  • 保留旧历史
  • 从现在开始改用 noreply
  • 开启命令行邮箱泄露拦截
  • 以后新提交全部走签名

什么情况下可以考虑重写历史

  • 私有仓库
  • 协作者很少,最好只有自己
  • 历史不复杂,强推成本可控
  • 你能接受所有 commit hash 变化

什么情况下通常不建议动

  • 公开仓库
  • 多人长期协作仓库
  • 已经有外部分支、fork、PR、issue 引用的仓库

很多人真正需要的,其实不是“把过去全部抹干净”,而是“从今天开始不再继续泄露”。


最后给三个直接可用的结论

场景一:只想让 GitHub 新提交显示 Verified

  • 直接配 SSH signing
  • 把公钥作为 Signing Key 加到 GitHub
  • 在 GitHub 仓库里开启 commit.gpgsign

场景二:既想 Verified,又不想暴露真实邮箱

  • 提交邮箱用 GitHub 的 noreply
  • 提交继续做 SSH signing
  • 同时打开 Keep my email addresses private

场景三:本地同时操作 GitHub 和 GitLab

  • 全局只配置签名能力,不默认全仓库自动签名
  • GitHub 仓库本地开启 commit.gpgsign true
  • GitLab 仓库保持普通邮箱和普通提交

这套方式通常最不容易互相污染。


参考文档

如果只保留一句总结,那就是:

noreply 管的是“显示哪个邮箱”,Verified 管的是“这个提交有没有被签名验证通过”,auth key 管的是“你能不能连上仓库”。