Git 仓库嵌套(嵌套 git / 子模块坑)

今天在备份博客的时候遇到了一个问题,主题目录无法提交到github仓库,最终发现是git仓库嵌套问题

什么是 Git 仓库嵌套?

一个 git 仓库里面,放了另一个完整 git 仓库。 也就是父仓库文件夹里面,某个子文件夹内部藏了一个 .git 文件夹。

你的主仓库(父git,有/.git)
└── themes/anzhiyu ← 这个文件夹里面又有一个 /.git

这就是仓库嵌套。父 git 会把这个子文件夹识别成一个特殊的 git 指针不会读取子文件夹里面任何文件

怎么产生的?

  1. git clone 地址 themes/anzhiyu clone 下来的项目自带内部.git
  2. 复制粘贴另一个 git 项目的整个文件夹过来,没删掉里面的.git

重点:哪怕你后来把子文件夹内部的 .git 删除了,父 git 的索引缓存还会记住它曾经是嵌套仓库,问题依旧存在!GitHub 显示蓝色箭头文件夹

现象

  1. 本地文件全都在,磁盘上看得见;
  2. git add 子文件夹,执行后 git commitnothing to commit, working tree clean,提交不上文件;
  3. git status会显示:xxx(modified content)
  4. 推上 GitHub:文件夹出现蓝色箭头,点不开,看不到里面真实源码,只存一个 commit 哈希指针。

GitHub 蓝色箭头 = git 子模块标记,仓库没有保存子文件夹的真实代码

两种处理方案

方案 A:把子仓库变成普通文件夹

彻底解除嵌套,把子文件夹当做普通文件交给父 git 管理。

  1. 删除子文件夹内部隐藏的 .git
# windows
Remove-Item -Recurse -Force themes/anzhiyu\.git
  1. 清除父 git 残留的缓存记录(必做!)
git rm --cached themes/anzhiyu

--cached只删 git 索引,本地文件完全不动,千万不要丢掉这个参数

  1. 如果有 .gitmodules 文件,删掉(子模块配置文件)
Remove-Item -Force .gitmodules
  1. 重新加入版本管理
git add themes/anzhiyu
git commit -m "转为普通目录"
git push

优点:简单,克隆仓库不需要额外命令。 缺点:子项目不能用 git 更新,后续更新只能手动下载覆盖。


方案 B:正式使用 Git Submodule(网上查到的没试)

如果你想保留子仓库的 git 版本,可以用子模块,而不是直接 clone 丢进去。

git submodule add https://github.com/xxx/xxx-theme.git themes/anzhiyu

会自动生成 .gitmodules 文件,记录子仓库地址。

子模块的坑:

  1. 别人克隆你的完整仓库,必须多执行一步才能拿到子模块文件
git clone 你的仓库地址
git submodule update --init --recursive

不执行,拉下来的themes/anzhiyu是空文件夹。 2. 更新子模块、提交、切换分支都有额外命令,新手极易踩坑。

Hexo 博客场景不推荐新手用 submodule

避坑指南

  1. 下载第三方项目 / 主题,优先下载 zip 压缩包解压,不要 git clone,从根源避免嵌套 git;
  2. 看到 GitHub 蓝色箭头文件夹,就代表这是子模块,没有存真实文件;
  3. 仅仅删除子文件夹内部.git不够,一定要执行git rm --cached清理父 git 旧缓存,否则旧记录还在;
  4. .gitignore不要写themes/*,会直接忽略整个主题目录。

快速排查命令

#查看文件夹下全部文件,包含隐藏的.git
ls themes/anzhiyu -Force

#查看当前git状态,看是否存在嵌套仓库标记
git status