网站部署问题总结:子模块、版本分歧与同步
📘 2026-07-08 部署问题总结:子模块、版本分歧与同步
前情提要: 子模块远程地址不是自己的仓库
本次修改是为了在网站底部悬挂ICP备案号,修改的文件是“…\my-blog\themes\butterfly\layout\includes\footer.pug”。
1 | .footer-other |
修改之后进行提交,发现这个文件属于文件夹themes\butterfly,这是一个仓库中的子模块,无法直接提交到主仓库。
1. 问题描述
在修改 Butterfly 主题并尝试提交时,发现:
主仓库提示子模块有修改:
1
modified: themes/butterfly (modified content)
在子模块内执行
git push时,提示权限错误:(幸好这次没有权限)1
2ERROR: Permission to xxxx/hexo-theme-butterfly.git denied to xxx(username).
fatal: Could not read from remote repository.或者成功推送到了开发者的原仓库(如果正好有权限),导致本地修改进入了官方仓库。
本质原因:子模块 themes/butterfly 的远程地址默认指向了开发者的原仓库(jerryc127/hexo-theme-butterfly),而不是自己的 Fork。
2. 错误做法及其后果
错误做法 1:直接修改子模块并提交
1 | cd themes/butterfly |
后果:
- 如果远程地址是开发者的仓库,且没有权限,推送会被拒绝。
- 如果恰好有权限,此次修改会直接进入官方仓库,影响所有使用该主题的人。
错误做法 2:强制推送到开发者仓库
1 | git push --force origin master |
后果:
- 覆盖开发者仓库的提交历史,极其危险。
- 可能导致开发者和所有使用该主题的人丢失提交记录。
3. 正确做法:使用 Fork 工作流
步骤 1:在 GitHub 上 Fork 主题仓库
- 访问
https://github.com/jerryc127/hexo-theme-butterfly - 点击右上角的 Fork 按钮
- 建议勾选 **”Copy the dev branch only”**,只复制你需要的分支
步骤 2:修改本地子模块的远程地址
1 | cd themes/butterfly |
步骤 3:提交并推送到你的 Fork
1 | git add . |
步骤 4:在主仓库中更新子模块引用
1 | cd ../.. |
4.如何防止再犯
4.1 每次推送前检查远程地址
1 | git remote -v |
确保输出指向你的 Fork,而不是开发者的原仓库。
4.2 在子模块中设置一个保护
在子模块中,可以添加一个别名来提醒自己:
1 | git config --local alias.push-origin '!echo "⚠️ 确认远程地址是 Fork 仓库!"; git push' |
4.3 使用 .gitmodules 控制子模块地址
确保 .gitmodules 中的 URL 指向你自己的 Fork:
1 | [submodule "themes/butterfly"] |
4.4 养成好习惯
| 操作 | 检查点 |
|---|---|
| 进入子模块 | 先 git remote -v 确认地址 |
| 修改子模块 | 确认分支正确(如 dev) |
| 提交子模块 | 确认推送目标是你自己的 Fork |
| 提交主仓库 | 确认子模块引用已被 git add |
5、快速诊断:你的子模块指向谁?
1 | cd themes/butterfly |
| 输出 | 指向 | 状态 |
|---|---|---|
git@github.com:jerryc127/hexo-theme-butterfly.git |
开发者原仓库 | ⚠️ 危险,请改为你的 Fork |
git@github.com:你的用户名/hexo-theme-butterfly.git |
你的 Fork | ✅ 安全 |
https://github.com/你的用户名/hexo-theme-butterfly.git |
你的 Fork(HTTPS) | ✅ 安全 |
6. 总结
| 错误做法 | 正确做法 |
|---|---|
| 直接向开发者仓库推送 | Fork 后推送到自己的仓库 |
在子模块中不做 remote -v 检查 |
每次推送前确认远程地址 |
| 修改后只提交子模块,不更新主仓库引用 | 修改后同时更新主仓库的子模块引用 |
| 在服务器上修改子模块 | 所有子模块修改都在本地完成 |
一句话总结:永远不要直接推送到你不拥有的仓库。先 Fork,再推送。 🎯
一、核心问题概览
| 问题 | 现象 | 根本原因 |
|---|---|---|
| 子模块版本落后 | 本地主题修改(备案号)不显示,服务器版本为旧提交 | 主仓库中的子模块引用未更新,服务器 git submodule update 拉取了旧版本 |
| 主仓库版本分歧 | 本地与服务器 main 分支提交哈希不一致,出现额外合并提交 |
在服务器上执行了 git pull 或 git push,产生了本地没有的合并提交 |
| 子模块注册信息丢失 | fatal: No url found for submodule path |
.gitmodules 或 .git/config 中的子模块配置被删除或损坏 |
| 服务器上执行 Git 操作权限不足 | chown: Operation not permitted |
钩子脚本以 git 用户执行 chown,只有 root 有权更改文件所有者 |
二、解决方案速查表
2.1 子模块版本落后(最常见)
问题:本地修改了主题并推送到了 GitHub,但服务器上的主题没有更新。
原因:主仓库中没有更新子模块的引用。
解决流程:
1 | # 1. 在子模块中提交并推送到 GitHub |
验证:在服务器上执行 git submodule update --init --recursive,然后 hexo generate。
2.2 主仓库版本分歧(本地和服务器提交哈希不同)
问题:本地 git log -1 和服务器网站目录的 git log -1 显示的提交哈希不同。
原因:在服务器上执行了 git pull 或 git push,导致产生了本地没有的合并提交。
解决流程:
1 | # 在本地拉取服务器上的提交,合并历史 |
验证:再次对比本地和服务器的提交哈希,应该一致。
2.3 子模块注册信息丢失(.gitmodules 中找不到子模块)
问题:fatal: No url found for submodule path 'themes/butterfly' in .gitmodules
原因:子模块的 .gitmodules 或 .git/config 配置被删除或损坏。
解决流程(在服务器网站目录执行):
1 | cd /www/wwwroot/www.xjelly.space |
2.4 服务器钩子中 chown 报错
问题:钩子脚本执行 chown 时提示 Operation not permitted。
原因:钩子以 git 用户执行,而 chown 需要 root 权限。
解决:在钩子中移除 chown 命令,只使用 chmod 修复权限。
1 | # 只修改权限,不更改所有者 |
三、经验教训
3.1 修改子模块的正确流程(每次都要执行两次提交)
| 步骤 | 操作 | 推送目标 |
|---|---|---|
| 1 | cd themes/butterfly |
— |
| 2 | git add . && git commit -m "..." && git push origin dev |
GitHub(你的 Fork) |
| 3 | cd ../.. |
— |
| 4 | git add themes/butterfly |
— |
| 5 | git commit -m "chore: 更新子模块引用" && git push origin main |
服务器裸仓库 |
关键点:第 5 步是让服务器知道子模块有新版本的关键,不能省略。
3.2 服务器网站目录的角色
- 网站目录是接收更新的地方,不是生产更新的地方。
- 在服务器上尽量避免执行
git commit或git push,除非你明确知道自己在做什么。 - 如果必须在服务器上提交,**一定要先
git pull,再git push**。
3.3 版本一致性检查命令
1 | # 检查主仓库版本 |
如果主仓库版本不一致,在本地执行 git pull origin main 同步。
如果子模块版本不一致,在服务器执行 git submodule update --init --recursive。
3.4 核心原则:所有修改都在本地完成
| 操作 | 推荐位置 | 不推荐位置 |
|---|---|---|
| 修改代码 | 本地 | 服务器网站目录 |
| 提交代码 | 本地 | 服务器网站目录 |
| 推送代码 | 本地 | 服务器网站目录 |
| 拉取代码 | 服务器钩子(自动) | 手动在服务器执行 |
| 生成静态文件 | 服务器钩子(自动) | 手动在服务器执行 |
四、快速诊断流程图
1 | graph TD |


