Git 不仅仅是一个版本控制工具,还提供了强大的高级操作功能,如历史重写、提交检索、数据块存储和恢复丢失的提交等。本章将深入探讨 git filter-branchgit rev-listGit 交互式存储 以及 恢复丢失的提交


20.1 使用 git filter-branch

git filter-branch 是 Git 提供的一个历史重写工具,允许批量修改 Git 提交历史,例如:

  • 从历史记录中移除敏感信息(如 API Key、密码)。
  • 规范化提交历史,例如修改作者信息。
  • 重写文件路径,迁移项目到新的结构。

20.1.1 使用 git filter-branch 的例子

示例 1:从历史记录中移除某个文件

如果不小心提交了一个敏感文件 config.json,可以使用以下命令从所有提交中移除该文件:

  1. git filter-branch --force --index-filter \
  2. "git rm --cached --ignore-unmatch config.json" \
  3. --prune-empty --tag-name-filter cat -- --all

然后强制推送更新到远程仓库(⚠️ 注意,这会改变历史,不建议用于已共享的分支):

  1. git push --force --all

示例 2:批量修改提交作者信息

如果需要修改所有提交的作者信息:

  1. git filter-branch --env-filter '
  2. if [ "$GIT_AUTHOR_EMAIL" = "old@example.com" ]; then
  3. export GIT_AUTHOR_NAME="New Name"
  4. export GIT_AUTHOR_EMAIL="new@example.com"
  5. fi
  6. ' --tag-name-filter cat -- --all

20.1.2 filter-branch 的滥用

⚠️ git filter-branch 会重写 Git 历史,不建议在多人协作的仓库中随意使用,否则可能导致分支混乱。

Git 官方推荐使用 git filter-repo(更快、更安全):

  1. git filter-repo --path config.json --invert-paths

20.2 我如何学会喜欢上 git rev-list

git rev-list 是 Git 提供的一个强大工具,可用于检索提交历史。它主要用于:

  • 按日期、文件、提交范围查找特定提交。
  • 统计提交数量,分析贡献度。
  • 找到某个文件的最早提交版本。

20.2.1 基于日期的检出

查看最近 7 天的提交:

  1. git rev-list --since="7 days ago" --all

查看 2023 年 1 月 1 日之后的所有提交:

  1. git rev-list --after="2023-01-01" --all

查看 2022 年 12 月 31 日之前的所有提交:

  1. git rev-list --before="2022-12-31" --all

20.2.2 获取文件的旧版本

如果想要找到某个文件的第一个提交,可以使用:

  1. git rev-list --max-parents=0 HEAD -- file.txt

如果需要恢复某个文件的旧版本:

  1. git checkout $(git rev-list -n 1 HEAD -- file.txt) -- file.txt

20.3 数据块的交互式暂存

Git 允许交互式暂存(Interactive Staging),使开发者可以选择性地提交代码块,而不是整个文件。

20.3.1 交互式暂存的基本操作

运行 git add -p 进入交互模式:

  1. git add -p

Git 会逐块显示文件变更,并提供以下选项:

  • y:暂存该部分
  • n:跳过该部分
  • s:分割当前块
  • e:编辑该块

示例:

  1. $ git add -p
  2. diff --git a/main.py b/main.py
  3. @@ -1,5 +1,6 @@
  4. def main():
  5. print("Hello, world!")
  6. + print("New feature added")
  7. Stage this hunk [y,n,q,a,d,s,e,?]?

如果不想提交 print("New feature added"),可以按 n 跳过该块。

20.3.2 git stash 结合数据块暂存

如果需要暂存部分更改,但不想提交,可以结合 git stash

  1. git stash push -p

然后可以随时恢复:

  1. git stash pop

20.4 恢复丢失的提交

有时候,我们可能会误用 git reset --hard,导致提交丢失。Git 提供了几种方法来恢复这些提交。

20.4.1 git fsck 命令

git fsck 用于检查 Git 数据库的完整性,同时可以列出丢失的提交:

  1. git fsck --lost-found

20.4.2 重新连接丢失的提交

如果 fsck 显示了丢失的提交哈希,例如 a1b2c3d,可以使用 git reflog 查找更详细的历史记录:

  1. git reflog

然后使用 git checkout 恢复提交:

  1. git checkout -b recovery-branch a1b2c3d

如果 git reflog 无法找到丢失的提交,可以尝试 git log 搜索 dangling commit

  1. git log --all --graph --decorate

如果找到了丢失的提交哈希,可以使用:

  1. git cherry-pick <commit-hash>

结论

本章介绍了 Git 的高级操作,包括:

  • git filter-branch(重写历史)
  • git rev-list(检索提交)
  • 数据块交互式暂存git add -p
  • 恢复丢失的提交git refloggit fsck

这些功能适用于 Git 高级用户,能够帮助开发者更高效地管理代码历史,并在紧急情况下恢复重要数据。