Skip to content

11 · 清理、维护与高级主题

日常用不到,但遇到大仓库、子模块、误删对象时知道「有这扇门」即可。不展开成专题。

git gc / git fsck

git gc

作用: 打包松散对象、删除过期 reflog 和不可达对象。Git 在合适的时候会自己跑。

改动范围: 对象库压缩。可能让很久以前的 dangling commit 再也找不回

bash
git gc

不要这样用:reset --hard / stash clear 完立刻 gc --prune=now,等于亲手关掉还原窗口。

git fsck

作用: 检查对象库完整性,列出 dangling blob / commit(没人引用但仍在磁盘上)。

改动范围: 只读。

bash
git fsck --lost-found

典型急救:曾经 add 过但从未 commit,后来 restore 丢掉了——blob 可能 dangling。lost-found 目录里能翻到文件碎片。见 急救手册

git archive

作用: 打一份不含 .git 的源码包,用于发交付物。

bash
git archive --format=zip --output=demo-v1.2.0.zip v1.2.0

不是备份仓库。备份历史请复制整个目录或用 git bundle

git bundle

作用: 把指定提交打成一个文件,在没有网络或只能传文件时当远程用。

bash
git bundle create repo.bundle main
git clone repo.bundle demo

浅克隆与部分克隆

仓库太大时:

bash
git clone --depth 1 <url>              # 只要最近提交
git fetch --unshallow                  # 事后补全

git clone --filter=blob:none <url>     # 部分克隆:先不拉文件内容,用时再取

浅仓库上 rebase / bisect / blame 可能不准。当完整历史工具不好用时,先怀疑是不是 --depth

sparse-checkout

只检出仓库的一部分目录,适合巨型 monorepo:

bash
git sparse-checkout init --cone
git sparse-checkout set apps/web

不改变远程历史。切回全量:git sparse-checkout disable

子模块 submodule(三板斧)

子模块是「主仓库里记录另一个仓库的某个 commit 指针」。

bash
git clone --recurse-submodules <url>
# 已经 clone 了:
git submodule update --init --recursive

改子模块里的代码后:

  1. 在子模块目录里 commit + push。
  2. 回到主仓库,会看到子模块指针变化,再 commit 这个指针。

常见坑: 只改了子模块工作区,忘了在子模块里 commit,主仓库无法记录「脏」状态以外的东西。手改子模块目录却去主仓库 reset --hard,子模块未提交改动会丢。

删除子模块步骤容易漏文件,需要时查当时 Git 版本文档,不要只删目录。

Git LFS

大二进制(模型、视频、设计稿)不该直接进普通 Git。LFS 把文件换成指针,实体存在 LFS 服务器。

  • 什么时候需要:单文件经常几十 MB,clone 变慢,历史爆炸。
  • 已经把大文件 commit 进去:后续要用 git lfs migrategit filter-repo 改写历史,所有人必须配合重克隆。这是少数「真的可能要重新拉项目」的情况,且要团队公告。

改写整段历史(了解即可)

从历史里抹掉密钥、剥离大文件:

  • 现在推荐:git filter-repo(需单独安装)
  • 旧:git filter-branch(慢、易用错)

做完必须 --force-with-lease 推所有分支和标签,每个协作者按公告重置本地。这不是个人急救手段。密钥仍要当作已泄露而轮换。

邮件补丁工作流

git format-patch / git am / git send-email 用于邮件列表贡献(Linux 内核等)。Web 托管 + PR 的团队用不到。

git notes

把额外说明挂到已有 commit 上而不改 SHA。很少用于应用开发。


上一章:10 · 标签 · 下一章:12 · 急救手册