> ## Content Index
> Fetch the complete content index at: https://blog.vercanti.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Git 进阶指南
- URL: https://blog.vercanti.com/git-jin-jie-zhi-nan/
- Published: 2026-08-28T14:34:24.000Z
- Updated: 2026-08-28T14:56:26.000Z
- Description: 最后更新：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。
- Author: yellowdog
- Tags: DevOps

最后更新：2026-03-31

> 官方文档：<https://git-scm.com/doc>  
> 适用版本：Git 2.40+（2026-05-08 核实）

相关文档：[GitHub Actions完全指南](https://blog.vercanti.com/github-actions-wan-quan-zhi-nan/) [Docker Compose完全指南](https://blog.vercanti.com/docker-compose-wan-quan-zhi-nan/)

---

## 1\. 内部原理

### 三个区域

| 区域                  | 说明                   |
| ------------------- | -------------------- |
| Working Tree        | 工作目录，实际文件            |
| Staging Area（Index） | 暂存区，git add 后的状态     |
| Repository（.git）    | 本地仓库，git commit 后的历史 |

### 对象模型

Git 用四种不可变对象存储数据：

| 对象类型   | 说明                          |
| ------ | --------------------------- |
| blob   | 文件内容（不含文件名）                 |
| tree   | 目录结构（文件名 + blob 引用）         |
| commit | 提交（tree + parent + 作者 + 消息） |
| tag    | 标签（指向 commit 的引用）           |

```bash
# 查看对象内容
git cat-file -t abc1234   # 查看对象类型
git cat-file -p abc1234   # 查看对象内容

# 查看提交树结构
git ls-tree HEAD
git ls-tree -r HEAD       # 递归列出所有文件

```

---

## 2\. 分支与合并

### rebase vs merge

```bash
# 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 — 摘取特定提交

```bash
# 从其他分支取一个提交应用到当前分支
git cherry-pick abc1234

# 取多个
git cherry-pick abc1234 def5678

# 取一段范围（不含 start）
git cherry-pick start..end

# 只应用变更，不立即提交
git cherry-pick --no-commit abc1234

```

### 解决合并冲突

```bash
git merge feature/login
# 出现冲突

# 查看冲突文件
git status

# 手动解决冲突后
git add conflicted_file.py
git merge --continue   # 或 git commit

# 放弃合并
git merge --abort

```

---

## 3\. 撤销与回退

### 修改最近一次提交

```bash
# 修改提交消息或补充文件
git add forgotten_file.py
git commit --amend --no-edit   # 不修改消息
git commit --amend -m "新消息"  # 修改消息

```

### reset — 回退到某个状态

| 模式           | 暂存区 | 工作区 | 适用场景             |
| ------------ | --- | --- | ---------------- |
| \--soft      | 保留  | 保留  | 撤销提交，保留所有改动在暂存区  |
| \--mixed（默认） | 重置  | 保留  | 撤销提交和 add，改动在工作区 |
| \--hard      | 重置  | 重置  | 彻底丢弃改动（危险）       |

```bash
# 撤销最近 3 个提交，改动回到工作区
git reset HEAD~3

# 回退到某个提交
git reset --hard abc1234

# 只取消暂存某个文件
git restore --staged file.py   # Git 2.23+

```

### revert — 安全撤销（已推送的提交用这个）

```bash
# 创建一个新提交，内容是撤销目标提交的改动
git revert abc1234

# 撤销最近一次提交
git revert HEAD

# 撤销一段范围（不含 start）
git revert start..end

```

### 找回"删除"的提交

```bash
# reflog 记录所有 HEAD 移动
git reflog

# 找到误删的提交 SHA，恢复
git checkout -b recovery-branch abc1234
# 或
git reset --hard abc1234

```

---

## 4\. stash — 临时保存

```bash
# 暂存当前工作区（不含未跟踪文件）
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\. 标签管理

```bash
# 创建轻量标签
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）

```bash
# 添加子模块
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 — 多工作区

在同一仓库同时工作在多个分支，无需切换：

```bash
# 在新目录创建另一个工作区（不同分支）
git worktree add ../hotfix hotfix/critical-bug

# 列出所有工作区
git worktree list

# 删除工作区（需先退出该目录）
git worktree remove ../hotfix

```

---

## 8\. 搜索与查询

```bash
# 搜索提交内容（变更中包含关键词）
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 引入提交

```bash
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/` 目录下，可执行文件。

```bash
# 常用钩子
.git/hooks/pre-commit       # commit 前运行（用于 lint/测试）
.git/hooks/commit-msg       # 检查 commit 消息格式
.git/hooks/pre-push         # push 前运行
.git/hooks/post-merge       # merge 后运行（如自动安装依赖）

```

```bash
#!/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 框架管理钩子

```yaml
# .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

```

```bash
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 技巧

```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：

```bash
git lfs track "*.h5"
git lfs track "datasets/**"
git add .gitattributes

```

### 敏感信息一旦提交就难以删除

即使删除文件再提交，历史中仍保留。需用 `git-filter-repo` 彻底清除：

```bash
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` 变更，后续该文件不再被追踪。

---

## 参见

[GitHub Actions完全指南](https://blog.vercanti.com/github-actions-wan-quan-zhi-nan/)  
[Docker初级指南](https://blog.vercanti.com/docker-chu-ji-zhi-nan/)