交互式添加 git add --interactive "Your edited hunk does not apply":您编辑的代码块无法应用

98

我正在尝试使用git add --interactive来选择性地将一些更改添加到我的索引中,但我不断收到“您编辑的补丁块无法应用。请重新编辑...”的消息。即使我选择e选项并立即保存/关闭编辑器,我仍然会收到此消息。换句话说,即使没有编辑补丁块,这个补丁也无法应用。

这是我正在使用的确切示例(我正在尝试组合一个小演示):

原始文件:

first change
second change off branch
third change off branch
second change
third change
fourth change

新文件:

Change supporting feature 1
first change
second change off branch
third change off branch
second change
third change
fourth change
bug fix 1
change supporting feature 1
我正在尝试展示如何使用git add --interactive仅将"bug fix 1"行添加到索引中。在文件上运行交互式添加时,我选择了补丁模式。它向我显示:

我想展示如何使用git add --interactive命令,只将“bug fix 1”行添加到索引中。在文件上运行交互式添加时,我选择了patch模式。它会呈现给我:

diff --git a/newfile b/newfile
index 6d501a3..8b81ae9 100644
--- a/newfile
+++ b/newfile
@@ -1,6 +1,9 @@
+Change supporting feature 1
 first change
 second change off branch
 third change off branch
 second change
 third change
 fourth change
+bug fix 1
+change supporting feature 1

我使用split命令,并在其后输入"no"来应用第一个差异块。对于第二个差异块,我尝试进行编辑。最开始我试图删除底部的行 - 但这并没有起作用。完全不修改差异块也不起作用,而我无法弄清原因。


1
确保的一件好事是,不要在文件中本来不存在的行的开头添加 -;这是一个差异,它不能删除不存在的行。因此,如果差异中的一行以 + 开头,并且您将其更改为 -,git 会感到困惑,因为现在标记为删除的行根本不存在(相反,该行被标记为添加,当标记为添加的行被标记为删除时,git 无法删除文件中不存在的行)。 - leeand00
4
请检查我的文本中的行尾符号(LF,CRLF),在我的情况下,只使用了一个LF而不是CRLF! - Alberto Rivelli
13个回答

127

这是像git-add文章中描述的吗?

手动编辑补丁非常强大,但如果您以前没有这样做过,则有点复杂。
需要记住的最重要的一点是: diff始终缩进一个字符,除了其他缩进之外。
字符可以是:

  • 一个空格(表示未更改的行),
  • 一个-表示该行已被删除,
  • 或者一个+表示该行已添加。

没有其他字符。它必须是空格、-或+。任何其他字符都会导致错误
(没有用于更改行的字符,因为这些行通过将旧行删除并添加新行来处理)。

由于您已经在您喜欢的文本编辑器中打开了diff(您确实配置了Git使用您喜欢的文本编辑器,对吧?),您可以随心所欲地进行操作 - 只要您确保结果diff应用无误即可。

这就是诀窍所在。如果您以前没有这样做过,Git会经常告诉您“您编辑的补丁不适用。再编辑一次?”,这会让您开始对自己无法弄清楚而感到厌烦,即使看起来很简单(或Git因为它无法弄清楚您想要什么)。

有件事经常会让我困扰,那就是我忘记了一个字符缩进。
我会将一行标记为-以进行删除,但在大多数文本编辑器中,它会插入-,而不是覆盖以前存在的空格。这意味着您正在向整行添加额外的空格,这反过来意味着diff算法无法在原始文件中找到/匹配该行,这又意味着Git会向您发出警告。

另一方面,差异(diff)仍然需要有意义。 "有意义" 意味着它可以被干净地应用。如何创建一个合理的差异似乎是一个有点黑暗的技能(至少对我来说),但你应该始终记住原始文件的外观,然后相应地计划 -s和+s。如果你经常编辑你的hunk,你最终会掌握它。

请参见git add -p上的提交(commit)

Ortomala Lokni答案参考了Joaquín Windmüller的博客文章 "选择性地选择要使用git提交的更改(或者我将编辑您的代码块)"

Git希望做的事情不是统计行数,而是在应用编辑后的代码块之前合并重叠的hunk。
这个问题已经在2018年中期被讨论,这将避免以下场景:

如果您拆分了一个hunk,编辑第一个子块,将一个尾随上下文行转换为删除,则如果您尝试暂存第二个子块,它将失败。


5
谢谢提供链接,但我已经看过了。我不是在添加或保留额外的行。问题出现在行号上,但我仍然不理解如何修复它。 - Josh
11
我没有用空格替换已删除的'-'符号,这导致了缩进出现问题。谢谢! - pedorro
请确保您不要误解空格部分。我认为所有未更改的行都应该只是一条带有黑色 - 而不仅仅是缩进字符的线...直到我理解了原因,我花了一个小时的时间来“编辑的块无法应用” :-/ - oligofren
@oligofren 我不确定我理解你的意思:你需要做什么才能使你编辑过的代码块生效? - VonC
1
@VonC:我最初认为我应该将“- foo”更改为“ ”(只是一个空格,而不是“一个空格和整行”)。花了我一段时间才明白它应该是“foo”。 - oligofren
显示剩余3条评论

61
当然,我来晚了,但是还是想要记录一下这个问题。去年在git邮件列表上讨论了这个问题,看起来似乎并没有太多变化。
这个特定的问题源自于拆分并且尝试编辑同一个块。最初由Jeff King发布的基本问题分析如下:
“嗯,好的,我明白了。'此diff适用'检查将两部分都提交给git-apply。但是当然第二部分永远不会正确地应用,因为它的上下文与第一部分重叠,但是没有考虑到这一点。”
“只使用编辑后的补丁进行检查是可行的。但这并不考虑您编辑的补丁在长期内是否会失败,具体取决于您是否接受了分裂补丁的另一半。而我们现在无法确定,因为用户可能没有告诉我们(他们可能跳过了第一半,然后在编辑步骤之后回到它)。 ”
Jeff在帖子中总结了一个非常实际的解决方法,并因此强烈建议:
“因此,总的来说,我认为拆分并编辑同一个块本质上是很危险的,并且会导致这些问题。而且因为编辑提供了功能的超集,所以我认为您应该只是编辑并根据您的首选项允许或不允许应用块的第一部分。”
通过仅选择编辑先前未拆分的块,您将不必处理行号。

8
谢谢,这确实比纠结行号容易多了。 - okonomichiyaki
5
这是我的问题。需要把我的“hunk”变小。我尝试使用交互式拆分,但拆分结果不是我想要的,所以决定手动编辑。但一直都出现错误。重新开始后,第一次尝试就成功了。 - Kyle s
4
这是这个帖子中最好的答案。不要分割和编辑,只需编辑。 - Dr_Zaszuś
在我的情况下,一个额外的问题来自于 Windows 行尾符,在 diff 文件中显示为 ^M。一旦我将文件保存为 CR 行尾符,交互式编辑补丁就可以通过了! - Dr_Zaszuś
谢谢,这对我很有帮助。我必须处理一个巨大的块,所以我将其分成了几部分,结果一切都崩溃了。保持不分割让一切正常工作。 - Matthias Fischer
为什么 Git 不直接说“抱歉,您无法编辑已拆分的块”,而是指责用户“不适用”?这是一个错误:错误是规范和结果之间的偏差。因此,当用户正确遵循编辑规则但无法工作时,这就是一个错误。 - user2394284

39

对于这个特定的例子,您需要调整块中的行号。更改以下行:

@@ -1,6 +2,8 @@

使其改为:

@@ -2,7 +2,8 @@

19
经过一番调查,我发现那些行显示了“从文件范围”和“至文件范围”。我不太理解将1改为2的逻辑背后的原因。我尝试了一下,它能正常工作,但我不明白为什么“从文件范围”会发生变化。无论是应用整个补丁还是只应用编辑后的块,原始文件都是相同的。你能否进一步澄清这个问题,或者向我指出一份关于统一差异格式的可靠参考资料?我在寻找这方面的资料时一直没有成功。 - Josh
10
@Josh: https://dev59.com/i3E85IYBdhLWcg3w9odJ 可以帮助,即使我不完全理解统一格式块。 @William +1 - VonC
5
在研究后,似乎这可能是一个漏洞。在你编辑了代码块之后,git会尝试通过检查所有代码块是否适用来验证补丁(这可能有些过度)。不幸的是,在这种情况下,这意味着正在检查先前的代码块(你没有应用该代码块),并且存在一些重叠,导致git apply --check失败。我不知道是否有优雅的解决方法;在这里,git可能正在采取过于谨慎的正确行动。 - William Pursell
28
关于更改行号的更多信息,请问我们为什么需要这样做?如何进行更改?每个数字代表什么意思?请进行说明。 - Bill
4
@WilliamPursell,你用的是哪个版本的Git?我刚刚换了新电脑,在运行Git v2.17.0时,我的补丁编辑突然变得无效了。请帮我看看。 - Dennis
显示剩余7条评论

25

在编辑 hunks(例如 @@ -1,6 +1,9 @@)时,正确地修改 hunk header 也很重要。Joaquin Windmuller 在他的 博客文章中揭示了编辑 hunk header 的秘诀。

编辑 hunks 的秘密

一开始编辑 hunks 可能会让人感到困惑,git 给出的指示虽然有帮助但并不足以入门。

# —||

# To remove ‘-’ lines, make them ’ ’ lines (context).

# To remove ‘+’ lines, delete them.

# Lines starting with # will be removed.

#

# If the patch applies cleanly, the edited hunk will immediately be

# marked for staging. If it does not apply cleanly, you will be given

# an opportunity to edit again. If all lines of the hunk are removed,

# then the edit is aborted and the hunk is left unchanged.

秘诀就是……数行:

  • 如果您删除以 + 开头的行,则将新行计数减1(修补程序标头的最后一位数字)
  • 如果您删除以 - 开头的行,则将新行计数加1(修补程序标头的最后一位数字)
  • 不要删除其他行(参考行)。

这应该可以让您快速修改修补程序并选择您想要的部分。


2
有没有一种方法可以自动化编辑块头或配置git以确定适当的行数? - Dennis
你可能可以编写脚本来自动化你最喜欢的编辑器。也许已经有一些插件可以做到这一点,但这取决于编辑器。 - Ortomala Lokni
2
我在Windows上使用git时遇到了这个问题。我发现你不必进行任何行计数或调整头文件。如果Vim是活动编辑器,只需在写入/退出之前将行结尾设置为Unix,git就会自动解决。:set ff=unix - Deon McClung

19

当您想保留一个已经标记删除的行时,可以执行以下操作:

 first line
-second line
 third line

在你想要保留第二行的位置时,确保将-替换为空格,而不是删除整行(就像你想要删除添加的行一样)。Git将使用该行作为上下文。


1
这对我来说不是很清楚,我以为 Git 告诉我将该行变成单个空格。 - JackHasaKeyboard

17

我最近通过阅读这个帖子找到了如何手动编辑的方法。

我使用的技巧是,如果我有一个类似于以下的差异:

+ Line to add
+ Line to add
+ Line I dont want to include
+ Line I dont want to include

关键是完全删除我不想要的两行,使得最终的diff看起来像:

+ Line to add
+ Line to add

虽然这对大多数人来说可能很明显,但直到今天我才明白它,所以我想分享一下我的经验。请告诉我这种方法是否存在任何风险。


3
非常感谢你!我至少花了一个小时试图将“+”更改为“' '”。 - samvdst
你知道,疯狂就是做同样的事情,却期望不同的结果。我在自言自语了20分钟后才意识到我只需要删除一些东西 :) - solidak
1
这应该是答案。简单明了,谢谢! - xPeaWhyTee

7

您可以手动编辑行号,在某些情况下这确实非常有用。但是,如果您不先拆分补丁,可能就可以避免这个特定的问题。

如果您发现后面需要编辑Git自动选择的内容,最好的方法是编辑整个补丁,而不是拆分、暂存一半,然后再编辑另一半。Git会更好地解决这个问题。


6

我来到这个问题是为了寻找解决同样问题的方法,但无法弄清如何更改行号(如上所建议)以便在我的情况下得到git的认可。然而,我发现了一种更好的方法,可以使用git gui实现。在那里,您可以选择要暂存的差异中的行,然后右键单击并选择“从提交中暂存行”。我记得git-cola也具有相同的功能。


这真的应该是答案。 git-cola 似乎可以在 Linux、Windows 和 MacOS 上运行。 - leeand00

6

如果您在编辑补丁时遇到“您编辑的块无法应用”之类的异常消息(很可能伴随着诸如“error: patch fragment without header at line...”之类的信息),其中一个原因可能是您使用的文本编辑器配置了去除行尾空格。这会导致严重问题,因为补丁会将空行编码为空格的行,如果使用此类编辑器保存,则包含空行的任何块都无法应用。因此,实际上,如果启用去除行尾空格,则包含任何未更改的空行的任何块在编辑后都无法应用。


5

当我遇到这个错误时,另一个问题是我的编辑文件保存时行尾符发生了改变。

我使用的是Windows操作系统,并且使用Notepad进行编辑(只能保存为Windows格式的行尾符),而我的代码是用Notepad ++编写的,设置为Unix / Linux风格的行尾符。

当我将默认git编辑器设置为Notepad ++后,我就可以对代码块进行修改。

git config --global core.editor "notepad++"

1
这对我起作用了,但我需要完整的 notepad++ 路径,并且这需要一段时间才能正确获取:git config --global core.editor'"C:/Program\ Files\ \(x86\)/Notepad++/notepad++.exe"' (根据 notepad++ 在您 PC 上的安装位置进行调整) - Annabel
1
我也遇到了完全相同的问题。原来是记事本引起的麻烦。一旦我将默认编辑器切换为Notepad++,一切都重新开始正常工作了。 - Johnny Oshika

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接