使用 Git add -p 暂存补丁
摘要
关于使用 git add -p 交互式暂存更改块的教程,允许选择性提交并保持更干净的版本控制历史。
暂无内容
查看缓存全文
缓存时间: 2026/07/29 21:57
# 使用 git add 暂存补丁
来源:https://www.simonholywell.com/post/git-add-p/
## 简介
如果你还没用过 `git add -p` 来暂存提交,那您就错过了一个好工具。它能让你交互式地暂存整个文件或其中一部分,让你的 Git 提交过程拥有更强的控制力。
## 为什么要这样做?
以下是我在工作流程中偏好使用 `git add -p` 的一些原因。最主要的是,它让我在暂存变更时同时审查代码,我经常通过这种方式发现错误。通过暂存时审查变更,我能捕捉到那些在初期编码或内容创作时悄悄溜进来的 bug、拼写错误和其他问题。
但还有一个额外好处:它允许我只暂存文件的一部分。Git(有点奇怪地)把这些部分称为“块”(hunks),所以下文我将沿用这个术语。这个功能在你有一堆变更、但又希望将它们分组到不同提交中时特别有用。想象一下,你在一个文件的不同部分做了几个相关的改动,借助 `git add -p`,你可以有选择地将这些改动暂存到一起,确保提交更干净、更有条理。
## 暂存文件的一部分
下面是一个界面示例,展示了差异并提示你“暂存此块?”。
```
diff --git a/main.mts b/main.mts
index e1132f2..8f7c279 100644
--- a/main.mts
+++ b/main.mts
@@ -1,2 +1,4 @@
export const add = (a, b) => a + b
+export const div = (a, b) => a / b
export const sum = (xs) => xs.reduce((acc, x) => sum(acc, x))
+export const avg = (xs) => div(sum(xs), xs.length)
(1/1) 暂存此块 [y,n,q,a,d,s,e,?]?
```
在最简单的形式下,我们可以输入 `y` 来暂存那段差异以便提交,或者输入 `n` 则不暂存。在这个例子中,我还没准备好提交 `avg` 函数,但想把 `div` 推送上去,所以我输入 `s` 将块拆分成更小的块。Git 接着问:
```
拆分为 2 个块。
@@ -1,2 +1,3 @@
export const add = (a, b) => a + b
+export const div = (a, b) => a / b
export const sum = (xs) => xs.reduce((acc, x) => sum(acc, x))
(1/2) 暂存此块 [y,n,q,a,d,j,J,g,/,e,?]?
```
所以我输入 `y` 来暂存这个块以便提交,Git 接着显示下一个块:
```
@@ -2 +3,2 @@
export const sum = (xs) => xs.reduce((acc, x) => sum(acc, x))
+export const avg = (xs) => div(sum(xs), xs.length)
(2/2) 暂存此块 [y,n,q,a,d,K,g,/,e,?]?
```
记着我只想提交 `div` 函数,所以我输入 `q` 退出交互式块暂存。交互结束后,我回到命令行提示符,然后可以接着执行 `git commit` 或其他必要命令。
## 检查是否生效
如果我运行 `git status` 查看暂存的文件,会发现该文件(`main.mts`)出现在两部分中:待提交和未暂存以待提交。这正是我们想要的,因为我们只暂存了文件的一部分!
```
位于分支 main
您的分支领先 'origin/main' 1 个提交。
(使用 "git push" 发布本地提交)
要提交的变更:
(使用 "git restore --staged <文件>..." 以取消暂存)
修改: main.mts
未暂存以备提交的变更:
(使用 "git add/rm <文件>..." 以更新要提交的内容)
(使用 "git restore <文件>..." 以丢弃工作区中的改动)
修改: main.mts
```
通过有选择地只暂存文件的一部分,我们成功地为即将进行的提交准备了一个单独的块——一个补丁。
## 其他选项
上面看到的选项列表(`[y,n,q,a,d,s,e,?]`)是缩略版,你可以输入 `?` 获取扩展的帮助文档。以下是一些在交互式块暂存中可用的响应选项,取自 [Git 文档](https://git-scm.com/book/en/v2/Git-Tools-Interactive-Staging#_staging_patches)。你会发现上面看到的列表里还有很多选项未列出。
- `y`:暂存此块
- `n`:不暂存此块
- `a`:暂存此块及文件中所有剩余的块
- `d`:不暂存此块及文件中所有剩余的块
- `g`:选择一个块跳转到
- `/`:搜索与给定正则表达式匹配的块
- `j`:暂不决定此块,查看下一个未决定的块
- `J`:暂不决定此块,查看下一个块(无论是否已决定)
- `k`:暂不决定此块,查看上一个未决定的块
- `K`:暂不决定此块,查看上一个块(无论是否已决定)
- `s`:将当前块拆分为更小的块
- `e`:手动编辑当前块
- `?`:打印帮助
## 何时不使用
我几乎每个工作日提交时都会使用 `git add -p`,但有两种情况不用:
1. 需要首次提交一个新创建的文件——新文件没有之前的版本可以用来对比,因此 `git add -p` 无法展示差异供你批准暂存。
2. 极少数情况下,当我想提交整个目录并且对其内容非常确信时,我会选择标准方式。不过即使在这种边缘情况,我也常常发现自己会用 `git add -p` 以获得更精细的控制。
## 总结
将 `git add -p` 融入你的工作流程,你会简化 Git 和提交过程。毫不夸张地说,我几乎在每次需要向 Git 提交变更集时都会使用这个技巧。它让我在暂存代码时轻松审查代码,并精确控制每个提交中包含什么内容。
相似文章
Git history 命令值得更多关注
文章重点介绍了新的 `git history` 命令及其 `fixup`、`reword` 和 `split` 子命令,这些命令提供了原子化且感知分支的提交历史编辑功能,带来了类似 jj 的益处,而无需切换版本控制系统。
git-absorb:自动的git commit --fixup
git-absorb自动为暂存的更改创建fixup提交,实现了与hg absorb类似的功能。它与git的autosquash集成,简化了应用代码审查反馈的过程,无需手动查找提交的SHA。
接受混乱的 git 历史
一篇博客文章,讨论两种 git 工作流理念——频繁提交与谨慎变基——并解释为何在大型团队中,鉴于团队的韧性,混乱的历史是可以接受的,文中还提到了 GitHub 的新堆叠 PR 功能。
使用 git rebase --onto 更新堆叠的拉取请求
解释如何在父提交被压缩或替换时,使用 `git rebase --onto` 更新堆叠的拉取请求。
Show HN: Codiff,本地差异审查工具
Codiff 是一款轻量级本地 diff 查看器,用于审查 Git 暂存和未暂存的更改,支持基于 LLM 的逐步讲解和内联审查评论。