如何在Powershell中正确生成和应用git补丁(vs bash)?

llew8vvj  于 2023-10-14  发布在  Git
关注(0)|答案(3)|浏览(134)

请注意以下简短的场景(这是在PowerShell中):

PS> git diff -U3 -r -M HEAD -- .\Metadata\LegacyTypeModules\xyz.Web.Main.draft.json | Out-File -Encoding ascii c:\temp\1.diff

PS> git apply --cached C:\temp\1.diff
error: patch failed: Metadata/LegacyTypeModules/xyz.Web.Main.draft.json:69
error: Metadata/LegacyTypeModules/xyz.Web.Main.draft.json: patch does not apply

这会失败,因为文件中的最后一行不是以CRLF结尾:

然而,在bash中运行时,同样的命令也可以工作:

$ git diff -U3 -r -M HEAD -- Metadata/LegacyTypeModules/xyz.Web.Main.draft.json > /c/Temp/2.diff

$ git apply --cached /c/Temp/2.diff

P11F70F@L-R910LPKW MINGW64 /c/xyz/tip (arch/1064933)

这两个补丁之间的区别是:

所以问题似乎发生了,因为Powershell用CRLF终止了通过管道的每一行,而bash保留了原始的行结尾。
我理解为什么会发生这种情况- Powershell操作对象,对象是字符串不包括EOL字符。当写入文件时,Powershell将对象转换为字符串(对于字符串,转换是nop),并使用默认的EOL序列来分隔行。
这是否意味着Powershell不能在EOL敏感的场景中使用?

polhcujo

polhcujo1#

的确:

  • PowerShell,直到v7.3.x,总是 * 解码 * 输出从外部程序 * 作为文本 *(使用[Console]::OutputEncoding)。
  • 然后,当行可用时,它通过管道逐行发送解码的输出。
  • 一个像Out-File这样的文件输出小程序在写入目标文件时总是使用 platform-native 换行符序列(Windows上的CRLF)来终止每个(字符串化的)输入对象(使用 * 它的 * 默认字符编码(或通过-Encoding指定的编码),这在技术上与用于 * 解码 * 外部程序输出的编码无关)。

换句话说:

Windows PowerShellPowerShell (Core) * 以及v7.3.x 中,*PowerShell管道(和重定向) 不 * 支持通过传递 * 原始二进制数据 *。

  • 但是,在 PowerShell(Core)v7.4+ 中,它们 * 确实 *(参见this answer)。
  • 请注意,**您必须使用>而不是Out-File**才能从外部程序(如git)捕获原始字节输出,就像在Bash中一样。
  • 换句话说:在v7.4+中,您的Bash命令可以在PowerShell中按原样使用
    v7.3的解决方法-
    • 手动 * 用LF换行符("n")连接并终止解码后的输出行,并将结果多行字符串按原样(-NoNewLine`)写入目标文件,如zdan's helpful answer所示。
  • 在这个简单的例子中,最容易的是委托给cmd.exe /c,因为**cmd.exe的管道和重定向 * 是 * 原始字节管道**:
cmd /c @'
git diff -U3 -r -M HEAD -- .\Metadata\LegacyTypeModules\xyz.Web.Main.draft.json > c:\temp\1.diff
'@

请注意,这里使用了一个here-string,以提高可读性,并便于任何嵌入式引用(此处不适用)。

jucafojl

jucafojl2#

您可以尝试使用join将CRLF替换为unix EOL:

(git command arguments . . .) -join "`n" | out-file c:\temp\1.diff -NoNewline
ymdaylpp

ymdaylpp3#

标准的diff(也称为patch)以LF行结尾来终止行。这是因为这是POSIX为diff的输出指定的。所有行必须包含LF行结尾。
当CR在修补程序中位于LF之前时,它被视为要修补的内容的一部分。因此,在您的情况下,补丁可能不适用,因为旧的内容被列为具有CRLF行结尾,而它没有。
不幸的是,PowerShell在这方面完全崩溃了,它的管道破坏了通过它们的数据。这对于任何类型的二进制数据都是如此。如果你正在使用任何一种设计用于在Unix上运行的工具,比如Git,你需要避免使用PowerShell的管道。

相关问题