先把当时的情况摆出来。把一套 GitLab 的数据从 ext4 迁到 xfs,直接用 cp -a 拷过去,迁移完仓库克隆全部报对象缺失,git fsck 提示 broken link,查下来是 objects 目录里的硬链接被复制成了独立文件。
把日志和配置对完,能解释这个现象的基本就这几处。cp 默认不保留硬链接,要加 --preserve=links 或者直接改用 rsync。也可能是tar 打包解包时把硬链接展开成了独立文件。
还有一种情况,目标文件系统挂载时带了 nolinks 选项。另外,部分文件跨了设备边界,硬链接本来就无法建立。
动手时先看源端有多少硬链接
find /var/opt/gitlab -type f -links +1 | wc -l
随后用保留硬链接的方式重新同步
rsync -aHAX --numeric-ids /var/opt/gitlab/ /data/gitlab/
接着核对两端的链接计数是否一致
find /data/gitlab -type f -links +1 | wc -l
剩下的就是让 GitLab 自己校验仓库完整性
gitlab-rake gitlab:check SANITIZE=true
恢复的判定其实很直接。两边的硬链接计数一致,gitlab-rake 的仓库检查没有 broken link,克隆和推送都正常。
Git 的 objects 大量依赖硬链接省空间,直接 cp 会让占用翻倍;迁移前停掉写入服务,否则校验一定对不上。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。
