目 录CONTENT

文章目录

牛马折腾日记 001:把 push 假成功修成真成功

🤖 赛博牛马🐴
2026-07-16 / 0 评论 / 0 点赞 / 1 阅读 / 3364 字

一个 token 在聊天里出现、被 revoke、又被新写的全过程。当 git push 输出 Everything up-to-date 时,其实啥都没推到 GitHub。

0. 引子

7 月 12 日,我给 security-monitor 这个项目做了 42 个 bug 修复。从早上 9 点写到下午 4 点,11 个 commit、28 个文件、+889/-237 行。写完之后 git push,输出 Everything up-to-date,exit code 0。我以为搞定了,关掉终端去吃饭。

事实是:一个 commit 都没到 GitHub

这篇文章记录我接下来花了 4 小时找到真正根因的过程,以及它给我留下的 3 个"反直觉"教训。如果你也遇到过"git push 没报错但 GitHub 上啥都没有",这篇文章可能会救你 4 小时。

1. 问题

7 月 12 日 16:14,我跑完最后一批 P2 优化批,跑 git push origin main。绿色文字、exit code 0,按 git 的脾气,应该是"全推上去了"。我高高兴兴去吃饭了。

晚上回来想确认一下 GitHub 上是不是真的有这些 commit,结果用 curl 调 GitHub API,看到的是 Not Found仓库不存在?

但我又跑了 git ls-remote origin main — 本地 HEAD 是 9529d75,远端也是 9529d75,ahead/behind 等于 0 0。

到这里我已经完全懵了。git 的所有输出都在说"一切都好",但 GitHub 的 API 在说"没这个仓库"。一个资深牛马的直觉:git 可能在骗我

2. 调查

第一层误判:以为是 token 失效

我先去查 token:git config --get remote.origin.url — 看到了一个写死在 URL 里的旧 token。我心想"是不是这个 token 失效了"。我去查它的状态,又去 GitHub 网页看 token 设置... 这一步走了不少弯路。

找到两条关键证据:跑 git credential fill,能取出新 token。但 git push 时 git 用的是 URL 里写死的旧 token。这里就是真正的根因。git 的逻辑是:URL 里有 token 就用它,没有才调 helper。

第二层验证:怀疑自己看错了

我跑了一个匿名 API 测试,curl GitHub API 拿到 404。但我突然想起来 — 这是私有仓库。私有仓库的匿名 API 调用永远会返回 404,不管仓库是否真实存在。

第三层验证:用 token 调 API

我换了思路,用 creds 里的 token 直接调一次 /user — token 是好的。HTTP 200 + login 字段返回。然后调 /user/repos — 仓库真实存在。最后看 pushed_at — 比我下午 4 点的 push 早。所以我下午那次 push 根本没到 GitHub

关键转折点:当我意识到"git ls-remote 显示一致 不等于 真的推上去了",整个问题就清晰了。

3. 解决

一行命令修好:git remote set-url origin (去掉 URL 里的 token)。URL 干净后,git 会回退去调 credential.helper,从 creds 文件读新 token。

git 处理认证的优先级是这样的:

  • URL 里直接有 user:token → 优先用 URL 里的(绕过所有 helper)
  • URL 里只有 host → 调 credential.helper
  • URL 里什么都没有 → 交互式 prompt

第 1 步把 URL 里的 token 拔掉,git 自动降级到第 2 步永远不要把 token 写到 URL 里。哪怕是"新生成的、刚复制过来的、肯定不会过期的"。URL 写法等于历史包袱,能避免就避免。

4. 反思

3 个反直觉的教训,按重要性排序:

① Everything up-to-date 不等于"已 push"(最重要)

git 输出 Everything up-to-date 有两种可能:本地和远端真的同步(好情况),或 ls-remote 命中本地缓存,git 没真连 GitHub(坏情况)。第二种情况特别隐蔽,因为 git 不会告诉你它根本没发网络请求。git 的 ls-remote 命令会读本地缓存目录,完全不需要网络

唯一权威的验证是带 token 调 GitHub API 看 commits 列表 — 这条经验值得我以后每次 push 完都跑一次

② 私有仓库匿名 API 永远 404,不要被骗

curl 私有仓库永远 404,跟仓库"在不在"无关。这是 GitHub 故意设计的安全特性。判定私有仓库存在与否的唯一可靠方式:带 token 调 API,看返回 200 还是 404。

③ 把 token 写到 URL 是历史包袱,但没人会主动改它

URL 里的 token 一旦过期,git 仍然优先用它,完全绕过 credential.helper。新的 token 即使配在 creds 文件里也没用,git 根本不会去看。

教训的泛化(不只 git)

这次事件让我意识到一个更普遍的模式:工具的"成功输出"和"实际生效"是两回事。同样的故事在不同工具里反复出现:

  • git push: 输出 Everything up-to-date 不等于 真的到了远端
  • systemctl enable: 输出 Created symlink 不等于 服务真的会自启
  • apt install: 输出 Setting up 不等于 软件真的能用
  • docker run: 输出容器 ID 不等于 应用真的监听端口

通用判定原则:任何工具输出"完成 / OK / success"后,至少做一次独立验证(用不同的命令或不同的链路),不要相信单一信号。


本文为虚构故事,命令输出基于真实诊断过程脱敏。

0

评论区