网易首页 > 网易号 > 正文 申请入驻

一个提交里塞了五处改动,怎么只拆出你要的那两处?

0
分享至

下午就要合一个 bug 修复,它偏偏和一处你想先吵一架的重构躺在同一个提交里。Agent 给这个提交起的名字叫Update checkout,动了五个文件。其中两个修的是客户今天就能看见的格式 bug,还配了测试;另外三个把写死的税率挪到接口后面,顺手把测试也重写了。这个提交只给你两个按钮:全要,或者全不要。


写代码的 agent 很容易走到这一步——任务说的是"清理 checkout",它一路上碰过的东西就全进了一个提交。放在以前,想把它拆开只能上交互式 rebase:标记edit、reset、分块重新暂存、提交两次、continue。

Git 2.54(2026 年 4 月发布)加了一条实验性命令专门干这个:git history split。你像用git add -p那样挑 hunk,Git 把它们写进一个新的父提交,所有建在其上的分支被移到重写后的历史上。没有待办清单,也不会卡在 rebase 进行中。

下面用一个一次性仓库复现:造一个 agent 风格的巨型提交,把它拆开,再用reword改消息、用fixup修补一个旧提交。

先把烂摊子故意造出来

split 和 reword 需要 Git 2.54 或更新,fixup 需要 2.55。用git --version确认。文件是几个小 PHP 类,但你不需要装 PHP 或 PHPUnit——Git 只认文本。

先在 main 上放起点。Money::format有个真 bug:1205 分输出成 12.5,因为分位没有补零。初始化仓库、建好 src 和 tests 目录、提交一个 "Initial checkout"。

然后扮演 agent。在任务分支上,一个提交同时修了补零、加了回归测试、抽出TaxRate接口、让 Checkout 依赖它、重写 Checkout 测试。接着第二个更小的提交落在上面,消息什么也没说。跑git show --stat HEAD~1,问题一目了然:五个文件、一条消息、两件不相干的事。

动手重写之前,先打个标签记住起点:git tag before-split。用标签,别用分支。默认情况下 git history 会移动所有从被重写提交派生出来的本地分支,放在顶端的备份分支会被一起挪走;而标签会留在你放它的地方。

用 git history split 拆开

把 split 指向那个巨型提交。它在顶端下面一个,正是以前需要 rebase 的场景:git history split HEAD~1。

Git 按路径顺序遍历这个提交的 hunk,逐个询问,按键和git add -p一样。y把 hunk 移进新提交,n留在原地,d连同该文件剩下的部分一起留下。对这个提交来说,选择是:

  • src/Checkout.php:d
  • src/Money.php:y
  • src/TaxRate.php:d
  • tests/CheckoutTest.php:d
  • tests/MoneyTest.php:y

然后编辑器会打开两次,两次都从 agent 的原始消息开始。第一次是给拆出来的那个提交——你挑中的 hunk,它成为新的父提交,写Fix zero-padding in Money::format。第二次是给留在原提交里的部分,写Extract TaxRate port from Checkout。作者身份保留原提交的作者。

如果两件事本来就分在不同文件里,用 pathspec 就能省掉按 d 的功夫,只有匹配的文件会被拿出来,其余留在原提交:git history split HEAD~1 -- src/Money.php tests/MoneyTest.php。

注意你没拆出去的东西:Checkout 测试的重写。旧测试调用new Checkout()不带参数,构造函数一旦需要 TaxRate 就会立刻崩。一个同时装着重构和旧测试的提交会让测试套件变红。重写后的测试要跟着逼它改的那处改动走。按"评审者会一起通过"的标准给 hunk 分组。

一个提交进去,两个提交出来:修复成为父提交,重构坐在它上面。接着确认什么都没丢:git log --oneline main..agent/checkout和git diff before-split agent/checkout。日志显示三个提交,原来是两个;diff 应该什么都不打印。split 只是重新分配 hunk,顶端代码不变。

第一次在真实分支上做?加上--dry-run。Git 会写出新对象但不移动任何 ref,并按git update-ref能读的格式打印 ref 更新。只想移动当前分支,就传--update-refs=head。

不用 rebase 的 reword 和 fixup

那个 "more fixes" 提交还在顶上。git history reword会在编辑器里打开任意提交的消息并就地重写,不碰工作区和索引,甚至在裸仓库里也能用。把它改成Document the TaxRate dependency in README。对 HEAD 来说,git commit --amend效果一样;reword 是给三四个提交之前、amend 够不着的地方用的。

然后评审发现一个缺口:修复没有覆盖金额小于 1.00 的测试。Git 2.55 加了git history fixup,把你暂存的改动折进更早的提交,再把后面的重放上去:git history fixup 'agent/checkout^{/Fix zero}'。这个^{/Fix zero}后缀会找到分支上消息匹配的最新提交。修复提交保留自己的消息和作者;想改消息就加--reedit-message。Git 2.56 加了git history drop,删掉一个提交并把它的后代重放到其父提交上。

如果 agent/checkout 已经推过,这些和任何 rebase 一样都是重写:用git push --force-with-lease推。想整个丢掉这次练习,在分支上执行git reset --hard before-split就回去了。

git history 拒绝做的事

手册页对限制写得很直白,而且大多是有意为之:

  • 不碰含合并提交的历史,那种情况用git rebase --rebase-merges
  • 任何会以合并冲突收尾的操作都会被拒绝。历史重写不该把你留在半成品状态,所以它直接中止,而不是中途停下。
  • Git 钩子"在当前时间点"不会运行。如果 commit-msg 钩子检查消息格式,它看不到你在 split 期间输入的消息。
  • 源码调用 hunk 选择器时禁用了编辑,所以不提供e。当一处修复和一处重构共享同一个 hunk,试试s把它切成更小的 hunk,或者退回git rebase -i

全选或全不选也是无效的,因为两个提交里会有一个是空的。截至 2.56,整条命令仍标记为实验性,并警告行为可能变化。要重排一段范围或把它移到新基底上,git rebase仍是那个工具;git history 一次只覆盖一处有针对性的编辑。

挑哪些 hunk 该在一起,是拆分里最难的部分,而 agent 的单个提交不会告诉你它按什么顺序干活。如果 agent 在一个回合里做了补零修复、下一个回合做重构,按回合看就能在你敲 pathspec 之前把路径给你。要是在 agent 提交之前就打开评审台,还能逐个文件暂存和提交,那就没什么可拆的了。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
足坛一夜动态:巴萨5-2!曼城3-2 利物浦2-1 拜仁6-1

足坛一夜动态:巴萨5-2!曼城3-2 利物浦2-1 拜仁6-1

念洲
2026-10-18 06:46:41
女主播曝光团播潜规则!陪大哥只是冰山一角,电击、自虐触目惊心

女主播曝光团播潜规则!陪大哥只是冰山一角,电击、自虐触目惊心

明天去看太阳
2026-10-16 19:47:35
个人养老,山东打响第一枪!

个人养老,山东打响第一枪!

A活着
2026-10-17 20:09:06
当不成总统了?特朗普最大金主放话:手里有猛料,将彻底扳倒川普

当不成总统了?特朗普最大金主放话:手里有猛料,将彻底扳倒川普

慕名而来只为你
2026-10-18 02:19:56
亲眼目睹藏族少女天葬之行,参加全过程后心悸:颠覆我对生死的认知

亲眼目睹藏族少女天葬之行,参加全过程后心悸:颠覆我对生死的认知

古怪奇谈录
2025-09-09 14:36:35
为啥美国用华氏度而中国用摄氏度?网友:他们就是吃饱了撑的!

为啥美国用华氏度而中国用摄氏度?网友:他们就是吃饱了撑的!

另子维爱读史
2026-10-17 21:34:53
离谱!月薪1800保安,被密集扫码打卡逼到离职,业主:我们要安全,不是打卡记录

离谱!月薪1800保安,被密集扫码打卡逼到离职,业主:我们要安全,不是打卡记录

火山詩话
2026-10-17 12:56:34
英超首位!队史129年来最佳开局!

英超首位!队史129年来最佳开局!

五星体育
2026-10-18 07:36:06
白宫第37任新闻秘书扎卡里亚上任不到一周就被解雇,据说是因为她虽是法律博士但不是律师

白宫第37任新闻秘书扎卡里亚上任不到一周就被解雇,据说是因为她虽是法律博士但不是律师

法律学堂
2026-10-18 00:10:23
苹果突然宣布国行 iPhone 18 Pro 全系列降价!

苹果突然宣布国行 iPhone 18 Pro 全系列降价!

XCiOS俱乐部
2026-10-15 15:35:31
央媒发文称别妖魔化东南亚,但普通人真别信

央媒发文称别妖魔化东南亚,但普通人真别信

凤眼论
2026-10-17 17:40:07
秦主任跳舞为什么会爆火?

秦主任跳舞为什么会爆火?

廖保平
2026-10-16 08:40:35
台湾县市长选举结果预测:国民党或可拿下五都,总计16县市执政权

台湾县市长选举结果预测:国民党或可拿下五都,总计16县市执政权

掉了颗大白兔糖
2026-10-18 03:16:45
全面绞杀开始?日本突然宣布,中方亮明底线:不认错,就没得谈

全面绞杀开始?日本突然宣布,中方亮明底线:不认错,就没得谈

疯狂小菠萝
2026-10-17 15:46:58
震惊!网传医院今后仅核心岗位保留编制,年成本30万,外包岗仅10万,招聘依旧竞争激烈,网友追问:博士临时工的时代来临了吗

震惊!网传医院今后仅核心岗位保留编制,年成本30万,外包岗仅10万,招聘依旧竞争激烈,网友追问:博士临时工的时代来临了吗

火山詩话
2026-10-17 09:32:09
上海的富婆王玲,和大16岁高曙光很恩爱,把二婚生活过成顶配

上海的富婆王玲,和大16岁高曙光很恩爱,把二婚生活过成顶配

情感大头说说
2026-10-17 04:30:28
佩莱格里尼:无法理解裁判的判罚;红牌让比赛失去平衡

佩莱格里尼:无法理解裁判的判罚;红牌让比赛失去平衡

懂球帝
2026-10-18 03:31:05
发现没:凡是校招进体制内单位的,简历都写满了这三行

发现没:凡是校招进体制内单位的,简历都写满了这三行

户外阿毽
2026-10-17 07:55:01
男子花1800点陪酒女,摸胸被报警!姑娘:1800是陪酒钱,摸胸得另加

男子花1800点陪酒女,摸胸被报警!姑娘:1800是陪酒钱,摸胸得另加

一丝不苟的法律人
2026-10-16 12:39:11
随着一场1-1,西甲争霸格局一夜大变:升班马排第8!巴萨24分8连胜领跑,马竞步步紧逼,皇马如今一地鸡毛

随着一场1-1,西甲争霸格局一夜大变:升班马排第8!巴萨24分8连胜领跑,马竞步步紧逼,皇马如今一地鸡毛

锐评利物浦
2026-10-17 10:20:28
2026-10-18 08:51:00
Ping值焦虑
Ping值焦虑
有态度网友ytd
210文章数 109关注度
往期回顾 全部

科技要闻

刘煜辉:99%的黄金分析师报告一钱不值

头条要闻

牛弹琴:法国又"燃烧"了 整个国家地图上到处都在冒烟

头条要闻

牛弹琴:法国又"燃烧"了 整个国家地图上到处都在冒烟

体育要闻

升级版杨瀚森再闯难关:当上开拓者第三中锋还得拼

娱乐要闻

庾澄庆罕谈前妻 撕下伊能静仅剩的体面

财经要闻

新一轮大跌源头,找到了!

汽车要闻

星瑞L PLUS限时售价10.97万元起 开启智混3L时代

态度原创

本地
艺术
家居
亲子
公开课

本地新闻

因新荣记出圈,这座浙东小城才是吃货天堂

艺术要闻

美到窒息!黛安笔下的午后“印象”,明媚又温柔,看完心情都亮了!

家居要闻

2026建博会(广州) 公装联探展交流活动

亲子要闻

炸鸡排摊前老板一声好嘞,藏着多少烟火气

公开课

李玫瑾:为什么性格比能力更重要?

无障碍浏览 进入关怀版