23、Git迁移与备份:仓库迁移、备份策略、恢复操作、跨平台迁移
聊到Git迁移和备份,我脑子里第一个蹦出来的场景是:几年前帮一个团队把几十个仓库从自建的GitLab搬到企业版GitHub。那会儿网络不稳定,仓库又大,折腾了两天才搞定。嗯,从那以后,我对迁移这件事就特别上心。
说白了,Git迁移和备份就是两件事:把代码安全地挪个地方,以及万一出事了能原样恢复。你想想看,代码是公司的命根子,这活儿干不好,后果很严重。
核心原则:迁移和备份的本质是「完整保留提交历史、分支、标签」。不是简单地把文件拷过去,而是把整个Git对象库搬走。
仓库迁移:换个地方住
仓库迁移,最常见的就是从一个Git服务器搬到另一个。比如从GitHub搬到GitLab,或者从自建服务器搬到云上。
最稳妥的方式:镜像克隆
我个人习惯用 --mirror 参数。这玩意儿会把所有东西都拉下来——分支、标签、引用,一个不落。
# 第一步:克隆裸仓库
git clone --mirror https://old-server.com/team/project.git
# 第二步:进入目录
cd project.git
# 第三步:添加新远程地址
git remote add new-origin https://new-server.com/team/project.git
# 第四步:推送所有内容
git push new-origin --mirror
小提示:用 --mirror 克隆出来的不是工作目录,而是裸仓库。你进去看会发现没有源码文件,只有 .git 里的那些对象。别慌,这是正常的。
我在项目中遇到过一种情况:旧服务器网络特别慢,一个仓库好几个G。这时候我会用 --depth 先浅克隆,但注意——浅克隆会丢失历史。所以如果要求完整历史,还是老老实实全量拉。
另一种方式:直接推裸仓库
如果你已经有裸仓库的备份文件,可以直接推过去:
# 在本地裸仓库目录中
git push --mirror https://new-server.com/team/project.git
这招特别适合离线迁移。先把裸仓库打包拷到U盘,到了新环境再推上去。
备份策略:别等出事了再后悔
备份这事儿,我吃过亏。有一次服务器硬盘坏了,才发现最近的备份是三个月前的。嗯,从那以后,我给自己定了个规矩:备份要自动化,要可验证。
方案一:裸仓库备份(推荐)
裸仓库是Git的「完全体」,备份它最省心。
# 创建裸仓库备份
git clone --mirror https://server.com/team/project.git project-backup.git
# 打包压缩
tar -czf project-backup-2024-01-01.tar.gz project-backup.git/
方案二:git bundle 打包
我个人挺喜欢 git bundle 的。它把整个仓库打包成一个文件,方便传输和归档。
# 创建 bundle 文件
git bundle create project.bundle --all
# 从 bundle 恢复
git clone project.bundle project-restored/
重要:bundle 文件是二进制的,别用文本编辑器打开。我曾经看到有人试图用记事本打开,结果全是乱码,还以为是文件坏了。
方案三:增量备份
仓库太大,每天全量备份不现实。可以用 git fetch 做增量:
# 第一次:全量
git clone --mirror https://server.com/team/project.git project-backup.git
# 之后每天:增量
cd project-backup.git
git fetch --all
这招我用了好几年,每天定时跑个脚本,省时省力。
| 备份方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 裸仓库 | 完整、可恢复 | 占用空间大 | 全量备份、迁移 |
| git bundle | 单文件、易传输 | 增量麻烦 | 离线传输、归档 |
| 增量 fetch | 省空间、快 | 依赖原始仓库 | 日常定时备份 |
恢复操作:从备份中重生
恢复操作,说白了就是备份的逆过程。但这里有个坑:恢复前一定要确认目标目录是空的,否则容易冲突。
从裸仓库恢复
# 解压备份
tar -xzf project-backup-2024-01-01.tar.gz
# 从裸仓库克隆出工作仓库
git clone project-backup.git project-restored/
从 bundle 恢复
# 直接克隆 bundle
git clone project.bundle project-restored/
# 或者先验证 bundle 完整性
git bundle verify project.bundle
警告:恢复后一定要验证!用 git log --oneline 看看提交历史是否完整,用 git branch -a 检查分支是否都在。我曾经恢复完才发现少了一个重要分支,就是因为备份时忘了加 --all 参数。
跨平台迁移:Windows、Linux、macOS 之间的坑
跨平台迁移,最头疼的不是Git本身,而是换行符和文件权限。
换行符问题
Windows 用 CRLF,Linux 和 macOS 用 LF。如果不处理,迁移后代码里全是 ^M 符号。
我建议在仓库根目录放一个 .gitattributes 文件:
# 设置文本文件的换行符
* text=auto
# 明确指定某些文件用 LF
*.sh text eol=lf
*.py text eol=lf
# 明确指定某些文件用 CRLF
*.bat text eol=crlf
*.ps1 text eol=crlf
文件权限问题
Linux 上的可执行权限,到了 Windows 就没了。Git 可以保存权限位,但需要设置:
# 查看文件权限
git ls-tree HEAD
# 设置可执行权限
git update-index --chmod=+x script.sh
路径大小写问题
Windows 和 macOS 默认不区分大小写,但 Linux 区分。这坑我踩过——在 macOS 上建了两个文件 Readme.md 和 README.md,推到 Linux 服务器上直接报错。
解决办法:在迁移前统一路径命名规范,或者设置 Git 大小写敏感:
# 让 Git 在 Windows/macOS 上也区分大小写
git config core.ignorecase false
我的经验:跨平台迁移前,先跑一遍 git fsck 检查仓库完整性。再跑 git gc 压缩一下对象库。这样能避免很多莫名其妙的问题。
好了,Git迁移与备份的核心内容就这些。记住一句话:迁移前备份,备份后验证,跨平台注意换行符和权限。做到这三点,基本不会出大问题。