侧边栏壁纸
博主头像
一笑痕

人生若只如初见,
是可喜亦或者是可悲?

  • 累计撰写 212 篇文章
  • 累计收到 7 条评论

别把整份文件一起暂存,Git 可以只收一个 hunk

2026-10-19 / 0 评论 / 8 阅读

别把整份文件一起暂存,Git 可以只收一个 hunk

同一个文件里改了两处,一处已经准备提交,另一处还在试。直接 git add notes.txt 会把两处一起放进暂存区。git add -p 可以先把差异一块块交出来,再决定每块是否进入下一次提交。

暂存的是差异块,不是文件副本

Git 有工作树和索引两个不同的位置。编辑器改动落在工作树,提交读取索引;git add 通常把文件当前内容放进索引。-p 则进入交互式补丁模式,将工作树相对索引的差异拆成 hunk,逐块询问是否暂存。

在临时仓库里,把 notes.txt 首行 alpha 改成 ALPHA,末行 delta 改成 DELTA。两处间隔了足够多的上下文,Git 将它们分成两个 hunk。脚本回答首块 n、末块 y,运行的是 Git 2.50.1(Apple Git-155)。输出的关键部分如下:

(1/2) Stage this hunk [y,n,q,a,d,j,J,g,/,e,p,?]?
(2/2) Stage this hunk [y,n,q,a,d,K,g,/,e,p,?]?
== cached diff ==
@@ -17,4 +17,4 @@ line-16
 line-17
 line-18
 line-19
-delta
+DELTA
== unstaged diff ==
@@ -1,4 +1,4 @@
-alpha
+ALPHA

第一块没有进索引,第二块进了。git status --short 显示 MM notes.txt:首列代表索引里有改动,第二列代表工作树仍有未暂存改动。完整输出和可重跑脚本分别在 tools/verify-git-add-p-hunks.log、tools/verify-git-add-p-hunks.sh。

提示符里的字母各管什么

最常用的是 y、n 和 q。y 暂存当前块,n 跳过当前块,q 退出交互。a 接受后续所有块,d 拒绝后续所有块;批量动作省按键,却也更容易把不该交付的差异带进去。

提示符还列出 s、e 等选项。s 尝试把当前块拆得更细,e 打开补丁供手工编辑。实测脚本只验证了 n 与 y,其余选项的效果没有逐一跑过。需要手工编辑时要格外谨慎,补丁格式如果改坏,Git 会拒绝应用;不确定时按 q 退出,再缩小改动范围。

提示符里的上下文还值得看一眼。每个 hunk 会带几行未修改文本,帮助判断选中的范围。上面的首块从文件开头开始,末块则显示 line-16 附近的内容,检查时能确认被暂存的是末尾那一处替换,而非整个文件。若差异由删除或新增多行组成,别只看块号;读完 - 与 + 行,才能判断块里是否混入了尚未完成的内容。

交互选择不改变工作树

git add -p 的选择只影响索引,不会替编辑器改文件。上面的首块被拒绝后,notes.txt 仍然是 ALPHA,并没有自动恢复成 alpha;它只是还没进入下一次提交。相反,末行的 DELTA 已经放入索引。之后若继续编辑这个文件,索引保存的旧版本和工作树的新版本还可能再形成额外差异,检查时要重新查看 git diff --cached 与 git diff。

这种分离也解释了一个常见误会:暂存部分改动后,状态里的 M 出现两次,不代表文件被复制出两个版本,也不是命令重复执行。前一个位置说明有已暂存改动,后一个位置说明仍有未暂存改动。提交只取索引里的部分,工作树中剩下的部分会留待后续处理。误暂存时,可以用 git restore --staged path/to/file 把整个文件从索引撤下,工作树改动会保留;若只想撤下一部分,可重新用 git add -p 整理索引。

是否能拆分取决于 hunk 之间的上下文距离。改动很靠近时,Git 通常会把它们合在同一个块;这时按 y 会一起暂存。按 s 可能拆开,但如果两个编辑紧挨着或相互依赖,也未必能再分。更稳妥的办法是把本来属于不同提交的内容分开编辑,或者在确认补丁后再用 e 手工删掉不想暂存的行。

提交前看索引里的内容

交互选择完成后,不要只看文件名。git diff --cached 检查实际会提交的差异,git diff 检查还留在工作树的部分。两者不是重复输出,它们分别回答索引里有什么、工作目录还剩什么。

git add -p path/to/file
git diff --cached -- path/to/file
git diff -- path/to/file
git status --short

这套检查适合一个文件混有不同目的的改动,尤其是准备拆成独立提交时。若同一行既改功能又改格式,hunk 级别仍可能太粗,人工编辑补丁也会增加出错机会;这种情况下,先还原并重新分开编辑,比硬凑一次选择更清楚。我不建议为了少敲几次键就接受不确定的块,提交边界比操作快慢更值得确认。

    🤞 分享