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-untrackedgit 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 Commitsfeat:, 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 变更,后续该文件不再被追踪。


参见

GitHub Actions完全指南
Docker初级指南

阅读更多

Web 安全基础

1. HTML 转义(服务端渲染必须): 2. CSP(Content Security Policy): 3. HttpOnly Cookie:防止 JS 读取会话 Cookie: 4. 前端框架防护: 攻击者在第三方网站构造一个表单,诱导已登录用户提交,浏览器会自动携带目标站的 Cookie。 触发条件: 1. 用户已登录目标网站(Cookie 有效) 2. 目标 API 仅凭 Cookie 识别用户身份 3. 请求来源未验证 1. CSRF Token(推荐): 2. SameSite Cookie: 3. 验证 Origin/Referer 头:

By yellowdog

HTTP 协议深度指南

HTTP(HyperText Transfer Protocol)是 Web 的基础传输协议,基于 TCP/IP,采用请求/响应模型。 相关文档:Web安全基础(/web-an-quan-ji-chu/) FastAPI完全指南(/fastapi-wan-quan-zhi-nan/) Nginx完全指南(/nginx-wan-quan-zhi-nan/) 幂等性:多次执行相同请求,服务器状态结果相同。PUT /users/1 多次执行结果一致;POST /users 每次创建新资源,非幂等。 浏览器直接从本地缓存读取,不向服务器发送请求。 缓存命中时,状

By yellowdog

系统设计基础

SLA 对照表: 选择建议:无状态服务(Web 层、API 层)优先水平扩展;数据库初期垂直扩展,达到瓶颈后考虑分库分表或读写分离。 缓存穿透(查询不存在的 key,每次都打到 DB): 缓存击穿(热点 key 过期,瞬间大量请求打到 DB): 缓存雪崩(大量 key 同时过期,或缓存服务宕机): 令牌桶 Python 实现: Redis 实现分布式限流(滑动窗口): URL 命名规则: Cursor 分页响应格式: 雪花算法结构(64 bit): 定义:分布式系统不能同时满足以下三个特性: 在分布式环境中 P 是必须保证的,所以实际是 CP vs AP

By yellowdog

算法思路与模板

二分查找要求序列有序,每次将搜索范围缩减一半,时间复杂度 O(log n)。 两个指针从两端向中间收缩,常用于有序数组。 滑动窗口维护一个满足条件的区间 left, right,right 不断向右扩张,条件不满足时收缩 left。 滑动窗口通用框架: 1. 确定"子问题":原问题可以分解为哪些规模更小的同类问题 2. 定义 dpi 或 dpij 的含义,要足够清晰 3. 推导状态转移方程 4. 确定初始状态(边界条件) 5. 确定计算顺序(确保依赖的子问题先计算) 每件物品最多选一次。dpj = 容量为 j 时的最大价值,逆序遍历容量防止重复选取。 每

By yellowdog