我先把这条报错放在前面,方便直接搜索到的人立刻对上号:
code复制remote: Push will publish a hidden email.
remote: Make email public or abandon related commits.
这个报错在 Gitee 上很常见,尤其是新注册账号、或者用 QQ 邮箱注册后自己又去开了“隐藏邮箱”开关的人。第一次 push 时看到这个英文提示,很多人会懵:我明明在 Gitee 上能看到仓库,本地 commit 也成功了,为什么偏偏 push 不上去?到底是谁拦了我的代码?
这篇文章会直接告诉你三件事:第一,Gitee 为什么会在 push 环节拦你;第二,怎么用最简单的方式放行;第三,如果你既不想公开邮箱、又想把代码推上去,应该怎么处理相关的 commit。整个排查和操作过程我会按实际踩坑的顺序写,涉及的 Git 命令都是可以直接复制执行的。
1. 这个报错到底是谁抛出来的:本地 Git 和 Gitee 的隐私校验机制
先理清一个概念:这条报错不是本地 Git 报的。本地 Git 在执行 git push 时,只会把对象打包上传到远端,收到远端 HTTP/SSH 服务的响应后,再把响应内容打印在终端里。所以你看那两行 remote: ... 开头的文本,其实是 Gitee 服务器端返回给你的业务提示,不是 Git 协议本身的错误。
Gitee 在接收 push 时,会扫描这次推送涉及的所有 commit 的 author 邮箱 和 committer 邮箱。它会拿这些邮箱去和你的账号设置做比对。如果在 Gitee 账号的邮箱设置里,你把某个邮箱设为“隐藏”状态,而提交里的邮箱又正好命中这个隐藏邮箱,gitee 就会认为:“这个用户把邮箱藏起来了,但这个 commit 又要公开显示,这样会泄露隐私,或者会产生无法对应账号的提交记录。”于是干脆拒绝整个 push。
这里面有一个容易误解的地方:很多人以为“隐藏邮箱”只是让第三方看不到,Gitee 服务器自己永远是能看到的。但问题恰恰在于——服务器能看到,服务器也知道那是你,服务器还知道你不希望公开。当一个 commit 的作者邮箱被标记为隐藏时,Gitee 的展示系统会给出一个替代邮箱占位符,比如 username@webmaster.gitee.com 之类的。可仓库的提交历史里真实邮箱已经被写进 Git 对象了,这是不可能动态改掉的。所以 Gitee 只能通过“拒绝推送”来逼你做一个选择:要么把邮箱公开放行,要么把历史里用了隐藏邮箱的 commit 处理掉。
我在本地 Git 配的 user.email 用的是注册 Gitee 的 QQ 邮箱,注册后又在设置里开了“邮箱隐藏”,然后造了个新仓库第一次 commit、push,当场复现了这条报错。终端完整输出大致是这样的:
bash复制$ git push -u origin master
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Writing objects: 100% (3/3), 222 bytes | 222.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), reused 0 (delta 0)
remote: Push will publish a hidden email.
remote: Make email public or abandon related commits.
remote:
remote: The following commits have a hidden email:
remote: d2f9a1c init
remote:
To gitee.com:xxx/test-private-email.git
! [remote rejected] master -> master (push declined due to email privacy)
error: failed to push some refs to 'gitee.com:xxx/test-private-email.git'
注意最后一行括号里的 email privacy,这说明推送是因为邮箱隐私策略被拒绝的。Gitee 非常贴心地列出了具体哪个 commit 有问题,就是那个 d2f9a1c init 提交。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 最简单的放行方式:去 Gitee 网页端把邮箱状态改成公开
如果你是第一次遇到,代码量不多,仓库也刚建立,那我建议选择最直接的方式:把隐藏邮箱改成公开,然后重新 push。五分钟内就能解决。
操作路径如下:
- 登录 Gitee,点击右上角头像,进入“设置”页面。
- 左侧菜单选“邮箱管理”,找到你注册时绑定的那个邮箱。
- 查看这一行后面的“公开”开关。如果之前点了隐藏,这里会是关闭状态(灰色 / 不勾选)。
- 把“公开”开关打开,或者点“设为公开”,保存。
- 回到终端,重新执行
git push -u origin master。
设置公开以后,Gitee 会再检查一次远端记录,发现发起 push 的账号绑定的邮箱已经是公开可见,那么历史 commit 里的对应邮箱就不会被视为“隐藏邮箱”了,推送会被放行。
这里不得不提醒一个细节:你改动的是 Gitee 账号的邮箱显隐状态,不需要改动本地 Git 的 user.email,也不需要修改 commit。因为那个 commit 里的邮箱地址没变,变的是 Gitee 对它的可见性标定。从“隐藏”转成“公开”,系统里就不再把它当成隐私风险。
如果你是在公司/Gitee 私有仓库做项目,并且这个邮箱本身就是你日常提交和工作沟通用的,直接公开问题不大。提交历史本身会显示邮箱,这本来就是 Git 的设计——它确实会暴露邮箱给所有能访问该仓库的人。公开的代价是任何人都可能给你发邮件,垃圾邮件风险会上升一点。如果你在意这个,别急,第三种方案更合适。
3. 不想公开邮箱时的完整处理路线:改 commit 里的邮箱,还是直接丢弃 commit
如果你跟我一样,不想把真实邮箱暴露在公网仓库里,那么你需要处理的不是 Gitee 端设置,而是本地 commit 历史。因为 Gitee 服务器那边已经没有别的可设置了,你再隐藏,push 就会被拦。
处理方式按要保留的提交数量不同,有三个路线可选。
3.1 提交数量少且确认内容不重要:直接删掉这些 commit
这是最粗暴的办法,适合刚 init 仓库只提交了一两次、代码没价值、或者只是想用 commit 做个测试的情况。
警告:这个操作会销毁你现在的提交历史。如果代码已经从别处 clone 过或推过别的远端,绝对不要这样做。
比如我当前的提交是:
code复制d2f9a1c (HEAD -> master) init
只有一条 commit,我可以用 update-ref 把 master 分支指针强制归零,然后再重新提交:
bash复制git update-ref -d HEAD
此时 Git 会让你回到“尚未提交”的初始状态,工作区文件还在。然后重新配置一个没被隐藏的邮箱,再执行 git add . && git commit:
bash复制git config user.email "no-reply@example.com"
git add .
git commit -m "init"
git push -u origin master
这样远端不会再有旧 commit,自然不会再触发 hidden email 校验。
如果你的隐藏 commit 不是最近一条,而是中间夹着几条有用的提交,别用 update-ref,那会连有用的提交一起干掉。这时用 rebase 来摘除会更好,但 rebase 对交互能力和 commit 理解要求较高。相比之下,更稳妥的是 3.2 的批量替换邮箱方案。
3.2 想保留提交但更换邮箱:用 filter-repo 或 filter-branch 重写历史
推荐优先使用 git filter-repo,它比 Git 自带的 git filter-branch 快得多,也安全得多。如果你的机器没装,先安装它。macOS 上用 brew,Ubuntu/Debian 上直接用 apt:
bash复制# macOS
brew install git-filter-repo
# Ubuntu / Debian
apt install git-filter-repo
然后执行:
bash复制git filter-repo --mailmap my-mailmap.txt
my-mailmap.txt 是 mailmap 映射文件,用来把我需要替换的旧邮箱映射到新邮箱。比如我在文件里写:
code复制New Name <new-public@example.com> <old-hidden-email@qq.com>
运行后,历史中凡是 Old Name <old-hidden-email@qq.com> 的作者身份全部会被替换成 New Name <new-public@example.com>。git filter-repo 默认会清理原始 origin remote,历史中旧邮箱会被全局重写。确认没问题后,把 remote 重新加上再推送即可:
bash复制git remote add origin git@gitee.com:xxx/test-private-email.git
git push -u origin master
如果你不方便安装第三方工具,也可以使用 Git 自带的 filter-branch,效果一样的,只是慢,而且官方一直提示它很危险。命令写法如下:
bash复制git filter-branch --env-filter '
OLD_EMAIL="old-hidden-email@qq.com"
CORRECT_NAME="Your Name"
CORRECT_EMAIL="new-public@example.com"
if [ "$GIT_AUTHOR_EMAIL" = "$OLD_EMAIL" ]; then
export GIT_AUTHOR_NAME="$CORRECT_NAME"
export GIT_AUTHOR_EMAIL="$CORRECT_EMAIL"
fi
if [ "$GIT_COMMITTER_EMAIL" = "$OLD_EMAIL" ]; then
export GIT_COMMITTER_NAME="$CORRECT_NAME"
export GIT_COMMITTER_EMAIL="$CORRECT_EMAIL"
fi
' --tag-name-filter cat -- --branches --tags
执行完同样需要重新加 remote 再推送。这里说一个经验教训:filter-branch 在 Windows 上执行时,环境变量语法要特别小心引号转义,容易踩坑。所以能装 filter-repo 就一定装 filter-repo,别在这上面省时间。
3.3 只改最近几条提交:交互式 rebase 定向修改
如果隐藏邮箱只出现在最近一两条 commit 上,比如你刚写完两个功能,正准备首次 push,那完全没有必要全局重写历史。用交互式 rebase 就能精准修改。假设当前有两条提交都有问题:
code复制d2f9a1c feat: second commit
f3a8b21 init
目标是改这两条的提交者邮箱并且保留提交时间等元数据。可以先执行:
bash复制git rebase -i --root
在打开的编辑器里,把两条 commit 前面的 pick 改为 edit,保存退出。Git 会停在第一条提交上,此时执行:
bash复制git commit --amend --author="Your Name <new-public@example.com>" --no-edit
然后继续:
bash复制git rebase --continue
Git 会停在第二条提交上,再执行一次同样的 --amend,然后 continue 到结束。确认提交历史干净后 push。
不过这个方案在提交数量多于七八条时会比较累,而且中途一旦记不住自己在哪容易改岔。所以实际操作的时候,我还是会根据“提交是否是最近刚做的”“是否已经推到过别的远端”“团队是否也有人拉过这个分支”这三条来选方案。没有协同风险的,随便折腾;有协同风险的,优先选择保留历史,和同事约定强推时间窗口。
4. 推送前先自查三件套:user.email、远端仓库设置和 commit 里的邮箱
很多时候这个 hidden email 报错其实是两个错误叠在一起:一个是 Gitee 的邮箱隐藏,另一个是本地 Git 的 user.email 配错了,或者根本没配对。我第一次配 Gitee 时,本地用的是全局配置里的旧 GitHub 邮箱,commit 提交者显示成别人,push 上去以后 Gitee 根本不认为那是我贡献的仓库,最后代码归属直接乱掉。
所以在动手改东西之前,请先跑三个自查命令。
第一个,看当前仓库的本地配置:
bash复制git config --local -l
重点看 user.name 和 user.email 两行。如果没输出,说明仓库只继承了全局配置。全局配置用下面命令查看:
bash复制git config --global -l
第二个,查看历史提交里实际记录的邮箱:
bash复制git log --format="%h | %an | %ae | %cn | %ce" -10
%ae 是作者邮箱,%ce 是提交者邮箱。如果其中有一个命中隐藏邮箱,那它一定会在 push 时被 Gitee 校验出来。
第三个,检查你当前 Gitee 账号绑定了哪些邮箱、这些邮箱是公开还是隐藏。这一步只能在网页端完成,命令行查不了。所以在第 2 节里的公开操作前,我建议先确认下到底哪个邮箱被隐藏了,避免你在终端改了半天本地 email,却改错了对象。
这三个自查动作做完以后,再决定走哪条方案,基本万无一失。
5. 如何在最开始就避免这种报错:设置邮箱的推荐姿势
就我的使用经验来看,与其每次 push 被拦再补救,不如在创建本地仓库之前就把邮箱配置理顺。这属于“十分钟预防,省掉一小时排查”的典型场景。
我的习惯是这样:
第一,全局配置用 Gitee 仓库要求的统一企业邮箱,或者 Gitee 官方支持的账号邮箱。如果仓库是个人空仓库,建议直接把全局邮箱设置成 Gitee 注册邮箱,并且保证这个邮箱在 Gitee 上是公开状态。
bash复制git config --global user.name "Your Name"
git config --global user.email "your-email@example.com"
第二,如果不同的平台使用了不同邮箱,比如 GitHub 用 A 邮箱、Gitee 用 B 邮箱,那么就放弃全局配置,改成针对仓库单独配置。我刚建一个新项目时,总是会在 clone/init 后立刻执行一次:
bash复制git config user.name "GiteeName"
git config user.email "gitee-email@example.com"
这时因为没有全局 user 的干扰,仓库级配置优先级更高,后续 commit 都会带上正确的身份信息。这样做还有一个附带好处:即便你将来把代码传到其他平台,也能通过提交者身份准确找到你本人。
第三,就是开头提到的 Gitee 隐藏邮箱开关。如果你真的非常不想让邮箱在任何地方可见,那我的建议是:不要在 Gitee 账号里启用邮箱隐藏功能的情况下用真实邮箱做 commit。你可以在 Gitee 里配置一个专门用于提交的对外邮箱,确保它在账号设置里是公开的;或者使用一个和注册邮箱不同的公开备用邮箱。实际上 Gitee 也有类似 GitLab 的 noreply 邮箱机制,只是入口相对隐蔽。如果你看到设置页面上有“为此邮箱启用额外的代码提交邮箱”之类的选项,可以看看它生成的格式,形如 你的用户名@webmaster.gitee.com。把本地 user.email 设成这个,就能保证 push 的时候不会被 hidden email 校验卡住,同时真实邮箱也保持隐藏。
我用这个方式在个人仓库试过一次,从 commit 到 push 全程没有再报 hidden email。简单说,核心思路就是:让提交里的邮箱是一个公开允许展示的邮箱,而不是注册邮箱本身。
6. 处理完 hidden email 后,Gitee push 还会遇到哪些连环坑
hidden email 只是 Gitee push 众多拦路虎中的一只。按我的经历,把它处理完以后,你大概率还会遇到下面这几个问题,尤其是新手朋友。
6.1 remote: error: Hook declined to update refs/heads/main
出现这个提示,通常是因为 Gitee 仓库默认分支名和你本地分支名不一致。Gitee 现在新建仓库默认分支可能是 master,也可能允许你在创建时指定成 main。而你本地执行的是 git branch -M main,把本地分支改成了 main,push 一个远端不存在的主分支,Gitee 的远程钩子就会拒收。
如果是这种情况,先登录 Gitee 仓库页,查看“分支”标签页里默认分支到底是什么,然后保持两端一致。比如远端是 master,你就在本地执行:
bash复制git branch -M master
如果远端是 main,你就改成 main。这个分支名不一致的问题常被误认为是权限不够,其实只要你确认自己是仓库管理员,基本就是分支名两端没对齐。
6.2 remote: error: GE007: Your push would publish a private email address
这个报错和本文主题很像,但文字略有不同。从 GE007 这个错误码可以看出来,是 Gitee 的邮箱隐私检查扩展。处理方式和正文里写的完全一样。甚至你可以把它当成本文描述报错的另一种写法,不必因为错误码不同就觉得问题变了。
6.3 报错“git did not exit cleanly” / “failed to push some refs”
这类报错信息量非常少,它只是 IDE 插件或 TortoiseGit 一类图形工具包装后的提示。真正的错误藏在上面几行。回到终端执行一次原始 git push origin HEAD --verbose,就能看到完整输出。
我在第一次尝试 Gitee pages 部署的时候就是被 IDE 包装的错误带偏了,在 IDE 设置里找了半天远程配置,最后才发现问题是远端仓库地址写错了。这类问题,强烈建议所有图形化工具操作前,先掌握命令行 push 的基础报错查看方法。终端是能给你完整真相的地方,IDE 反而把细节藏起来了。
7. 一个小结:push 失败时,按序排查邮箱、分支名和远端地址
最后分享一个我自己的排查顺序,它能覆盖大部分 push 失败场景,顺便帮你避免反复在同样的坑里打转。
先看报错有没有 remote: ... 前缀。有 remote 前缀说明请求已经到达 Gitee 服务器,问题出在服务器侧的校验。这种时候,本地怎么试都没有用,去网页端查设置。如果没有 remote 前缀,那就是本地 Git 走不到服务器,常见于网络、SSH key、远端地址、本地分支跟踪状态出问题。翻出 git remote -v 和 ssh -T git@gitee.com 这两条命令先确认连通性。
接下来,就是判断服务器侧的问题到底属于哪一类:
- 提示
hidden email或private email address,先考虑邮箱隐藏设置,再考虑重写提交邮箱。 - 提示
Hook declined或 “protected branch”,去仓库设置里看分支保护规则、是否开启了在线编辑检查。 - 提示找不到仓库或权限不足,检查仓库地址和 ssh key 是否给你的账号加了 push 权限。
按这个顺序排查,我这些年遇到的所有 Gitee push 问题基本都能在十分钟内定位。希望这篇文章能帮你在遇到 hidden email 时少走点弯路。如果你最后真的需要重写提交历史,记得等全部操作成功后再删本地的 filter-repo 备份 refs/original,别急着清理;哪天发现哪次提交内容被改出问题,还能捞回来。
