Git 进阶指南
最后更新:2026-03-31 相关文档:GitHub Actions完全指南(/github-actions-wan-quan-zhi-nan/) Docker Compose完全指南(/docker-compose-wan-quan-zhi-nan/) Git 用四种不可变对象存储数据: rebase 交互界面可用命令: 在同一仓库同时工作在多个分支,无需切换: 钩子脚本放在 .git/hooks/ 目录下,可执行文件。 reset --hard 会重写历史,推送后需要 force push,会破坏其他人的本地仓库。已推送的提交应使用 revert。
最后更新:2026-03-31
官方文档:https://git-scm.com/doc
适用版本:Git 2.40+(2026-05-08 核实)
相关文档:GitHub Actions完全指南 Docker Compose完全指南
1. 内部原理
三个区域
| 区域 | 说明 |
|---|---|
| Working Tree | 工作目录,实际文件 |
| Staging Area(Index) | 暂存区,git add 后的状态 |
| Repository(.git) | 本地仓库,git commit 后的历史 |
对象模型
Git 用四种不可变对象存储数据:
| 对象类型 | 说明 |
|---|---|
blob |
文件内容(不含文件名) |
tree |
目录结构(文件名 + blob 引用) |
commit |
提交(tree + parent + 作者 + 消息) |
tag |
标签(指向 commit 的引用) |
# 查看对象内容
git cat-file -t abc1234 # 查看对象类型
git cat-file -p abc1234 # 查看对象内容
# 查看提交树结构
git ls-tree HEAD
git ls-tree -r HEAD # 递归列出所有文件
2. 分支与合并
rebase vs merge
# merge — 保留完整历史,产生合并提交
git merge feature/login
# rebase — 重写历史,线性提交,更整洁
git rebase main
# 交互式 rebase — 整理提交历史
git rebase -i HEAD~5 # 编辑最近 5 个提交
rebase 交互界面可用命令:
| 命令 | 作用 |
|---|---|
pick |
保留提交 |
reword |
保留但修改提交消息 |
edit |
暂停,允许修改内容 |
squash |
与上一个提交合并(保留消息) |
fixup |
与上一个提交合并(丢弃消息) |
drop |
删除提交 |
cherry-pick — 摘取特定提交
# 从其他分支取一个提交应用到当前分支
git cherry-pick abc1234
# 取多个
git cherry-pick abc1234 def5678
# 取一段范围(不含 start)
git cherry-pick start..end
# 只应用变更,不立即提交
git cherry-pick --no-commit abc1234
解决合并冲突
git merge feature/login
# 出现冲突
# 查看冲突文件
git status
# 手动解决冲突后
git add conflicted_file.py
git merge --continue # 或 git commit
# 放弃合并
git merge --abort
3. 撤销与回退
修改最近一次提交
# 修改提交消息或补充文件
git add forgotten_file.py
git commit --amend --no-edit # 不修改消息
git commit --amend -m "新消息" # 修改消息
reset — 回退到某个状态
| 模式 | 暂存区 | 工作区 | 适用场景 |
|---|---|---|---|
--soft |
保留 | 保留 | 撤销提交,保留所有改动在暂存区 |
--mixed(默认) |
重置 | 保留 | 撤销提交和 add,改动在工作区 |
--hard |
重置 | 重置 | 彻底丢弃改动(危险) |
# 撤销最近 3 个提交,改动回到工作区
git reset HEAD~3
# 回退到某个提交
git reset --hard abc1234
# 只取消暂存某个文件
git restore --staged file.py # Git 2.23+
revert — 安全撤销(已推送的提交用这个)
# 创建一个新提交,内容是撤销目标提交的改动
git revert abc1234
# 撤销最近一次提交
git revert HEAD
# 撤销一段范围(不含 start)
git revert start..end
找回"删除"的提交
# reflog 记录所有 HEAD 移动
git reflog
# 找到误删的提交 SHA,恢复
git checkout -b recovery-branch abc1234
# 或
git reset --hard abc1234
4. stash — 临时保存
# 暂存当前工作区(不含未跟踪文件)
git stash
# 包含未跟踪文件
git stash -u
# 附加描述
git stash push -m "WIP: login page"
# 查看 stash 列表
git stash list
# 恢复最新 stash(保留 stash 记录)
git stash apply
# 恢复并删除 stash 记录
git stash pop
# 恢复指定 stash
git stash apply stash@{2}
# 删除指定 stash
git stash drop stash@{2}
# 清空所有 stash
git stash clear
5. 标签管理
# 创建轻量标签
git tag v1.0.0
# 创建附注标签(推荐,含元数据)
git tag -a v1.0.0 -m "Release version 1.0.0"
# 给历史提交打标签
git tag -a v0.9.0 abc1234
# 查看标签
git tag
git show v1.0.0
# 推送标签
git push origin v1.0.0 # 推送单个
git push origin --tags # 推送所有
# 删除标签
git tag -d v1.0.0 # 本地删除
git push origin --delete v1.0.0 # 远程删除
6. 子模块(Submodule)
# 添加子模块
git submodule add https://github.com/user/lib.git libs/lib
# 克隆含子模块的仓库
git clone --recursive https://github.com/user/project.git
# 或
git clone https://github.com/user/project.git
git submodule init
git submodule update
# 更新子模块到最新
git submodule update --remote
# 遍历所有子模块执行命令
git submodule foreach git pull
7. worktree — 多工作区
在同一仓库同时工作在多个分支,无需切换:
# 在新目录创建另一个工作区(不同分支)
git worktree add ../hotfix hotfix/critical-bug
# 列出所有工作区
git worktree list
# 删除工作区(需先退出该目录)
git worktree remove ../hotfix
8. 搜索与查询
# 搜索提交内容(变更中包含关键词)
git log -S "function_name" --oneline
# 搜索提交消息
git log --grep="fix bug" --oneline
# 搜索文件内容(当前工作区)
git grep "TODO"
# 按作者过滤
git log --author="Alice" --oneline
# 按日期过滤
git log --after="2026-01-01" --before="2026-03-01" --oneline
# 查看某文件的历史
git log --follow -p -- src/utils.py
# 查看某行代码最后由谁改动
git blame src/utils.py
git blame -L 10,20 src/utils.py # 只看第 10~20 行
bisect — 二分查找 bug 引入提交
git bisect start
git bisect bad # 当前提交是坏的
git bisect good v1.0.0 # v1.0.0 是好的
# Git 自动 checkout 中间提交,测试后标记
git bisect good # 这个提交正常
git bisect bad # 这个提交有问题
# 找到 bug 引入提交后
git bisect reset # 恢复原来状态
# 自动化 bisect(脚本返回 0 为好,非 0 为坏)
git bisect run python test.py
9. 钩子(Hooks)
钩子脚本放在 .git/hooks/ 目录下,可执行文件。
# 常用钩子
.git/hooks/pre-commit # commit 前运行(用于 lint/测试)
.git/hooks/commit-msg # 检查 commit 消息格式
.git/hooks/pre-push # push 前运行
.git/hooks/post-merge # merge 后运行(如自动安装依赖)
#!/bin/bash
# .git/hooks/pre-commit
# 在 commit 前运行 black 和 mypy
echo "Running pre-commit checks..."
black --check .
if [ $? -ne 0 ]; then
echo "Black formatting check failed. Run 'black .' to fix."
exit 1
fi
mypy src/
if [ $? -ne 0 ]; then
echo "mypy type check failed."
exit 1
fi
使用 pre-commit 框架管理钩子
# .pre-commit-config.yaml
repos:
- repo: https://github.com/psf/black
rev: 24.1.0
hooks:
- id: black
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.3.0
hooks:
- id: ruff
pip install pre-commit
pre-commit install # 安装到 .git/hooks/
pre-commit run --all-files # 手动运行
10. 常用工作流
Git Flow(适合版本发布型项目)
main ←─── release/1.0 ──→ (tag v1.0)
develop ←─── feature/login
←─── hotfix/critical-bug ──→ main
Trunk-Based Development(适合 CI/CD 项目)
main(主干) ←─── feature/short-lived
每次 PR 必须通过 CI 才合并
通过 Feature Flags 控制功能上线
分支命名约定
feature/user-login 新功能
bugfix/fix-null-pointer Bug 修复
hotfix/critical-crash 紧急修复(直接从 main 切出)
release/1.2.0 发布准备
chore/update-deps 维护任务
11. .gitignore 技巧
# 忽略所有 .env 文件
.env
.env.*
# 只保留 .env.example
!.env.example
# 忽略目录
__pycache__/
.pytest_cache/
dist/
build/
# 忽略特定扩展名
*.pyc
*.log
*.tmp
# 只在根目录忽略(不在子目录)
/node_modules/
# 全局 gitignore(适用于所有仓库)
git config --global core.excludesFile ~/.gitignore_global
12. 踩坑与注意事项
不要对已推送的提交使用 reset --hard
reset --hard 会重写历史,推送后需要 force push,会破坏其他人的本地仓库。已推送的提交应使用 revert。
rebase 不要在共享分支上使用
rebase 重写提交 SHA,共享分支(如 main)上使用会导致其他人历史混乱。只在自己的私有分支上使用。
大文件不要提交到 Git
Git 不适合存储大二进制文件(模型权重、数据集)。使用 Git LFS:
git lfs track "*.h5"
git lfs track "datasets/**"
git add .gitattributes
敏感信息一旦提交就难以删除
即使删除文件再提交,历史中仍保留。需用 git-filter-repo 彻底清除:
pip install git-filter-repo
git filter-repo --path secret.key --invert-paths
最佳实践
rebase 整理提交历史,merge 保留集成记录:特性分支合并主干前用 rebase 整理 commit,保持线性历史;主干合并特性分支用 merge --no-ff 保留合并节点,方便回溯"这批功能何时合入"。
git stash 配合 --include-untracked:git stash 默认不暂存未追踪的新文件,切换分支前用 git stash push --include-untracked -m "desc" 保存完整工作状态。
用 git bisect 二分定位回归提交:比逐个 checkout 测试快得多,git bisect start; git bisect bad; git bisect good <hash> 自动引导缩小范围。
git worktree 同时检出多分支:同一仓库在不同目录检出不同分支,无需切换即可并行工作:git worktree add ../feature-branch feature。
提交信息遵循 Conventional Commits:feat:, fix:, refactor:, chore: 前缀让 CHANGELOG 自动生成工具(如 semantic-release)能解析提交类型,也便于 code review 快速了解意图。
常见陷阱
陷阱:git push --force 覆盖他人提交
现象: 团队成员推送的提交被 force push 覆盖,工作丢失。
原因: --force 直接替换远程 ref,不检查是否有新提交在本地之上。
解决: 始终用 --force-with-lease 替代 --force,若远程有新提交(他人推送)则拒绝强制推送,保护他人工作。
陷阱:rebase 已推送的共享分支
现象: git rebase 后 push 报 "non-fast-forward",或他人的本地分支历史被破坏。
原因: rebase 改写提交哈希,若其他人基于这些 commit 工作,他们的历史与新历史不兼容,需要 force pull 和 rebase,造成混乱。
解决: 只对本地未推送的提交 rebase,或只对个人特性分支(无他人协作)rebase;已 push 的公共分支用 merge。
陷阱:.gitignore 无法忽略已追踪的文件
现象: 在 .gitignore 中添加文件路径,但该文件仍出现在 git status 中。
原因: .gitignore 只对未追踪(untracked)文件生效,已经被 git 追踪的文件必须先 git rm --cached <file> 从索引中移除。
解决: git rm --cached <file> 移除追踪,再提交 .gitignore 变更,后续该文件不再被追踪。