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

问题描述 投票:0回答:3

请观察以下简短场景(这是在 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敏感场景下根本无法使用?

bash git powershell newline
3个回答
3
投票

确实:

  • PowerShell 总是解码来自外部程序的输出作为文本(使用

    [Console]::OutputEncoding

  • 然后,当线路可用时,它会通过管道逐行发送解码的输出。

  • 文件输出 cmdlet(例如

    Out-File
    )然后总是使用 platform-native 换行序列 - Windows 上的 CRLF - 在写入目标文件时终止每个(字符串化)输入对象(使用 its 默认值)字符编码(或通过
    -Encoding
    指定的编码),这在技术上与用于 解码 外部程序输出的编码无关)。

换句话说:

  • Windows PowerShellPowerShell(核心) 直至 v7.3.xPowerShell 管道(和重定向)支持通过传递原始二进制数据

  • 他们,但是,PowerShell(核心)v7.4+ - 请参阅这个答案

v7.3-的解决方法:

  • 手动使用LF换行符(

    "`n"
    )连接并终止解码的输出行,并将生成的多行字符串按原样(
    -NoNewLine
    )写入目标文件,如zdan的有用答案所示.

  • 在这个简单的情况下,最容易委托给

    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以提高可读性并易于任何嵌入引用(此处不适用)。


2
投票

您可以尝试使用

join
将 CRLF 替换为 unix EOL:

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

2
投票

标准 diff(也称为补丁)以 LF 行结尾终止行。这是因为这就是 POSIX 为

diff
的输出指定的内容。所有行必须包含 LF 行结尾。

当补丁中 CR 位于 LF 之前时,它被视为要补丁内容的一部分。因此,您的情况下的补丁可能不适用,因为旧内容被列为具有 CRLF 行结尾,而事实并非如此。

不幸的是,PowerShell 在这方面完全被破坏了,它的管道破坏了通过它们的数据。对于任何类型的二进制数据尤其如此。如果您使用任何设计在 Unix 上运行的工具(例如 Git),则需要避免使用 PowerShell 的管道。

© www.soinside.com 2019 - 2024. All rights reserved.