12

我使用三个提交创建了一个补丁

git format-patch <revision_three_commits_ago>

这会创建三个补丁文件,我从我的笔记本上邮寄并在我的台式计算机上阅读邮件(两者都是 Windows 机器)。

当我现在做

git am --3way --ignore-space-change *.patch

补丁适用,但我没有为提交获得相同的 SHA1 ID。在修补的文件中搜索了一下,我发现我的台式计算机上修改后的行以 . 结尾LF,而笔记本(我创建补丁的地方)上的修改行以CR LF.

git am所以,我的第一个想法是不打电话--ignore-space-change,但这给了我一个错误(补丁不适用)。

我怎么知道git format-patchgit am关于如何处理行尾(msysgit 1.7.4)?

在我可以应用补丁之前,我真的必须使用 VIM 并将文件格式从 更改为UNIX吗?DOS


编辑:甚至用 VIM 修改补丁文件都没有帮助:我想,set ff=dosa:%s/^M//g会有所帮助,但它没有!

在我看来,应用补丁应该会产生完全相同的内容和相同的提交哈希,就像我从创建补丁的另一个仓库中提取的一样。我想错了吗?

4

4 回答 4

21

在玩了各种选项(core.autocrlfcore.eol)之后,我发现使用

git am --keep-cr

可以解决问题(但会导致有关尾随空格的警告)。

无需手动编辑补丁文件或其他污垢。

但是,(当然)哈希值与nikai的回答中描述的不同......感谢 nikai 将我指向哈希值。

在我的 notebook-desktop-scenario 中,我想将一些更改从笔记本离线传输到台式计算机,但是当我在桌面上应用补丁然后git pull desktop从笔记本上执行时,repos 不应该出现分歧,也不应该出现两次相同的提交.

为了实现这一点,我做了以下事情:

  1. 在桌面上,使用上述方法应用补丁git am --keep-cr ...
  2. 在笔记本上,到 a git pull desktop,这导致补丁引入的每个提交发生两次(一次用于原始笔记本提交,一次用于修补并拉入桌面提交)
  3. 现在(在master笔记本的分支上),发出一条git rebase desktop/master线索No changes -- Patch already applied消息并踢出由桌面提交替换的原始笔记本提交
于 2011-07-13T09:47:41.740 回答
7

Git 2.3.0(2015 年 2 月)将提出另一个新选项:--transfer-encoding为了指定要使用的传输编码 (quoted-printable, 8bit, base64),而不是仅依赖 --keep-cr.

git send-email手册页
git am手册页

请参阅Paolo Bonzini ( )提交 8d81408bonzini

git-send-email: 添加--transfer-encoding选项

邮件列表线程git am详细说明了在以 CRLF 行结尾的存储库中应用带有“”的补丁时出现的问题。
在线程中的示例中,存储库源自“ git-svn”,因此无法使用core.eol它和它的朋友。

现在,最好的选择是使用“ git am --keep-cr”。
但是,当补丁创建新文件时,补丁应用进程将拒绝新文件,因为它找到的是“ /dev/null\r”字符串而不是“ /dev/null”。

问题是SMTP 传输是 CRLF-unsafe
通过电子邮件发送补丁与通过“”传递补丁相同dos2unix | unix2dos
新引入的 CRLF 通常是透明的,因为git-am剥离了它们。该keepcr=true设置保留了它们,但它主要是偶然工作的git am,在具有混合 LF 和 CRLF 行结尾的存储库中具有“”工作流将是非常有问题的。

对此的MIME 解决方案是引用可打印传输编码
这不是我们想要默认启用的东西,因为它使收到的电子邮件看起来很可怕。
但是,它非常适合在存储库中存储 CRLF 行结尾的项目。

引用打印的唯一缺点是,如果维护者使用“”,引用打印补丁将无法应用git am --keep-cr
这是因为解码后的补丁将在行尾有两个回车符。
因此,还要添加对base64 传输编码的支持,这使得收到的电子邮件完全不可能在MUA(邮件用户代理)之外查看,但确实可以正常工作。

该补丁覆盖了所有基础,包括仍然生活在 80 年代后期的用户,还提供了 7 位内容传输编码,拒绝发送包含非 ASCII 字符的电子邮件。
最后,“8bit”将添加一个 Content-Transfer-Encoding 标头,否则什么也不做。

git send-email 的文档现在将包括:

--transfer-encoding=(7bit|8bit|quoted-printable|base64)

指定用于通过 SMTP 发送邮件的传输编码。
遇到非 ASCII 消息时,7bit 将失败。

当存储库包含包含回车的文件时,Quoted-printable 可能很有用,但会使原始补丁电子邮件文件(从 MUA 保存)更难以手动检查。

默认是 ' sendemail.transferEncoding' 配置值的值;如果未指定,git将使用 8bit 并且不添加 Content-Transfer-Encoding 标头。


在 Git 2.32(2021 年第二季度)中,“ git mailinfoman(因此“ git amman)学习了“ --quoted-cr”选项来控制如何处理以 CRLF 结尾的以 base64 或 qp 包装的行。

请参阅Đoàn Trần Công Danh ( )的提交 59b519a提交 133a4fd提交 f1aa299提交 0b68956(2021 年 5 月 10 日)和提交 dd9323b提交 d582992(2021 年 5 月 6 日) 。(由Junio C Hamano 合并 -- --提交 483932a中,2021 年 5 月 16 日)sgn
gitster

mailinfo: 如果在解码的 base64/QP 电子邮件中发现 CRLF,则发出警告

签字人:Đoàn Trần Công Danh

当 SMTP 服务器收到 8 位电子邮件消息时,可能只有 LF 作为行尾,其中一些决定将所述 LF 更改为 CRLF。

一些邮件列表软件在收到 8 位电子邮件消息时,决定将这些消息编码为 base64 或引用打印。

如果一封电子邮件通过上述邮件服务器传输,然后由此类邮件列表软件分发,收件人将收到一封电子邮件,其中包含一个带有 CRLF 编码的补丁,该补丁被编码在另一个编码中。

因此,这样的 CR(在 CRLF 中)不能被“ mailsplit”删除。
因此,无法干净地应用邮寄的补丁。在野外已经观察到
这样的事故。

如果找到这样的 CR(作为 CRLF 的一部分),让我们给我们的用户一些警告,而不是默默地拒绝这些消息。

警告将是:

warning: quoted CRLF detected
于 2015-01-31T22:29:11.030 回答
3

这里有一个类似的问题:显然相同的提交给出不同的 sha1,为什么?

作为一个简短的回顾,git cat-file commit <sha>应该能够缩小树、父母、电子邮件、日期、作者或提交者的姓名是否不同,或者是否在提交消息中引入了额外的 '\n'。

于 2011-07-03T22:28:48.657 回答
2

简短的回答:git am --committer-date-is-author-date

长话短说:我刚刚发现我在同一条船上尝试在两个存储库之间进行sneakernet提交。在尝试了git am's 选项之后,我注意到文件 ID 总是匹配的,但是连续运行git am会为相同的选项生成不同的提交 ID。事实证明,有两个时间戳——您通常看到的“作者”时间戳和创建提交时的“提交者”时间戳。后者在默认情况下设置为当前时间git am。您需要--committer-date-is-author-date保持日期同步的选项,这反过来将使您的提交 ID 同步。

正因为如此,我想说git bundle如果这是您环境中的一个选项,那将更加可靠。

于 2012-06-28T15:37:40.953 回答