Git
Git 是现代软件的基石。到 2025 年,像稀疏检出和 Scalar(适用于单体仓库)等特性正在成为主流。
何时使用
- 分支与协作:跨分布式团队管理功能隔离、拉取请求、主干开发和代码审查。
- 历史重写与清理:线性化提交图、压缩 WIP 提交、通过
git rebase -i编辑提交信息,然后合并到主分支。 - 自动化缺陷查找:通过
git bisect在数千个修订版本中通过二分搜索隔离引入回归的提交。 - 并发工作空间上下文:使用
git worktree在不进行暂存或上下文切换的情况下处理紧急热修复。 - 大型仓库扩展:使用 Git 稀疏检出、Scalar 和浅克隆优化大型单体仓库的性能。
快速入门
# 克隆仓库并创建一个新功能分支
git clone https://github.com/myorg/project.git
cd project
# 使用现代命令创建并切换到新分支
git switch -c feature/auth-flow
# 暂存、提交并推送到远程并设置上游跟踪
git add .
git commit -m "feat(auth): implement oauth2 authorization code flow"
git push -u origin feature/auth-flow
核心概念
三棵树架构(工作树、索引、HEAD)
Git 管理文件时涉及三种不同的状态,而不是简单地跟踪修订之间的变更:
# 1. 工作树:编辑器中修改但未暂存的文件
echo "export const API_URL = 'https://api.v2.internal';" >> config.ts
# 2. 索引(暂存区):准备用于下一次提交的内容
git add config.ts
# 3. HEAD:活动分支上最后一次提交的快照
git diff --staged # 检查暂存区与 HEAD 之间的差异
git commit -m "chore(config): update internal API endpoint"
有向无环图(DAG)与不可变对象
Git 中的每个提交都是一个不可变的节点,指向父哈希和包含文件快照的根树对象。
# 检查任意提交哈希或 HEAD 后面的原始对象
git cat-file -p HEAD
# 输出:
# tree 4b825dc642cb6eb9a060e54bf8d69288fbee4904
# parent 8f3d1e1c3a628a58a98b47cf7d12a9e32049e712
# author Alice <[email protected]> 1727420400 +0000
# committer Alice <[email protected]> 1727420400 +0000
#
# feat(auth): implement oauth2 authorization code flow
现代分支导航(git switch vs git restore)
现代 Git 将功能过载的 git checkout 命令拆分为专用的操作:
# 分支切换(替代 git checkout <branch>)
git switch main
git switch -c feature/payments # 创建并切换
# 文件恢复(替代 git checkout -- <file>)
git restore src/app.ts # 丢弃工作目录中未暂存的更改
git restore --staged src/app.ts # 将文件从索引移回工作树(取消暂存)
变基与合并策略
- 合并(
git merge <branch>):保留完整的历史上下文,创建一个双亲合并提交。非常适合集成长期存在的发布分支。 - 变基(
git rebase <upstream>):将主题提交线性回放到上游 HEAD 之上,避免出现混乱的“铁轨”图。非常适合在 PR 审查前清理功能分支。
# 将功能分支干净地变基到最新的 main
git switch feature/auth-flow
git fetch origin main
git rebase origin/main
常见模式
使用 Git 工作树进行多分支开发
问题:为了切换分支修复紧急生产 bug 而需要暂存未完成的修改。
解决方案: 同时将多个分支检出到独立的目录中:
# 为热修复分支创建并行工作树目录
git worktree add ../hotfix-branch main
# 在单独的目录中处理热修复,不影响当前工作区
cd ../hotfix-branch
git commit -am "fix: patch critical auth vulnerability"
git push origin hotfix-branch
# 完成后清理工作树
cd ../project
git worktree remove ../hotfix-branch
使用交互式变基清理拉取请求历史
问题:功能分支包含数十个杂乱的“WIP”、“fix typo”或“checkpoint”提交。
解决方案:在提交拉取请求之前,交互式地压缩并清理历史。
# 交互式地变基最后 4 个提交
git rebase -i HEAD~4
# 在交互式编辑器中:
# pick 8f3d1e1 feat(auth): add token generation
# squash 4b825dc fix typo in token payload
# squash a1c94e2 add missing import
# reword 91f7a02 feat(auth): add refresh token endpoint
使用 Git Bisect 进行自动化回归查找
问题:一个 bug 被引入到 500 个提交中的某个位置,但具体是哪个提交未知。
解决方案:使用自动化测试执行脚本进行二分搜索。
# 开始二分查找会话
git bisect start
git bisect bad HEAD # 当前 HEAD 是错误的
git bisect good v2.1.0 # v2.1.0 已知是正常的
# 在每个二分步骤上自动运行测试脚本
git bisect run npm test -- --runInBand
# Git 会定位到第一个导致测试套件失败的提交
git bisect reset
最佳实践(2026)
应做:
- 使用
git switch和git restore:避免使用功能过载的git checkout,以防止意外切换分支或覆盖文件。 - 使用
--force-with-lease推送:防止覆盖远程分支上同事的提交。 - 启用后台维护:运行
git maintenance start以优化包文件、提交图和获取性能。 - 使用 SSH/GPG 签名提交:保证生产流水线中提交作者身份的真实性。
- 编写约定式提交:使用标准化的前缀(
feat:、fix:、chore:、refactor:)自动化语义版本控制和变更日志。
不应做:
- 不要强制推送到受保护分支:绝不要重写
main、master或共享发布分支的历史。 - 不要提交机密信息或凭据:使用
.gitignore和git-secrets/trufflehog;一旦提交,即使之后删除凭据也会保留在包文件对象中。 - 不要直接使用大型二进制文件:将大型模型权重或媒体文件存储在 Git LFS(大文件存储)或 S3 中。
- 不要合并脏的工作树:在拉取或变基之前,先暂存或提交更改,以避免意外文件冲突。
故障排查
| 错误 | 原因 | 解决方案 |
|---|---|---|
fatal: refusing to merge unrelated histories | 从独立初始化且没有共享根提交的仓库拉取。 | 运行 git pull origin main --allow-unrelated-histories。 |
HEAD detached at ... | 检出的是特定提交哈希而不是分支名称。 | 从当前位置创建分支:git switch -c recovery-branch。 |
Merge conflict in file.txt | 并发的提交修改了不同分支上相同的行。 | 解决冲突标记(<<<<<<<),暂存文件(git add),然后运行 git commit。 |