将sed设为GIT_EDITOR在git交互式变基中无法正常工作的原因
问题分析与解决方案
为什么sed -iEn "2 p"会导致异常结果?
你的问题出在两个关键点上:
sed版本的
-i选项行为差异
如果你用的是BSD sed(比如macOS自带的版本),-i选项必须显式指定备份后缀——哪怕不需要备份,也要写成-i ''。你的命令-iEn会被解析成-i E(把原todo文件备份成todo-fileE),虽然理论上原文件会被改成仅保留第2行,但这种解析差异可能导致sed没有正确覆盖原文件,git最终读取的还是原始的todo列表(保留了pick bar和pick baz两行),所以rebase时会重新应用bar和baz,就出现了重复的baz提交。git对todo文件的处理逻辑
就算sed正确把todo文件改成仅保留pick baz,git也会把baz提交重新应用到foo上(因为baz原本的父提交是bar),生成一个新的baz提交。但如果sed没改对文件,git就会按原始todo执行,在原历史后再新增一次baz提交,就出现了你看到的重复记录。
而你测试的sed -iE "2! s/^pick/drop/" --能正常工作,是因为:
- 没有用
-n选项,sed会输出所有处理后的行,todo文件里会明确保留drop bar和pick baz两行,逻辑清晰; - 直接把不需要的提交标记为drop,完全符合git对todo文件的处理规则,不会有歧义。
可靠的实现方式
如果想用sed实现保留foo和baz、丢弃bar的需求,推荐用以下两种明确的写法(兼容BSD和GNU sed):
方式1:直接删除bar对应的行(第1行)
GIT_EDITOR='sed -i'' -E "1 d" --' git rebase -i HEAD~2
方式2:把bar的pick替换为drop
GIT_EDITOR='sed -i'' -E "1 s/^pick/drop/" --' git rebase -i HEAD~2
这两种写法都能准确修改todo文件,避免版本差异和逻辑歧义,结果完全符合预期。
内容的提问来源于stack exchange,提问作者Piotr Siupa
相关产品推荐
相关产品推荐

