如何将 Git 补丁应用于具有不同名称和路径的文件?

Posted

技术标签:

【中文标题】如何将 Git 补丁应用于具有不同名称和路径的文件?【英文标题】:How to apply a Git patch to a file with a different name and path? 【发布时间】:2013-05-07 17:44:05 【问题描述】:

我有两个存储库。一方面,我对文件./hello.test 进行了更改。我提交更改并使用git format-patch -1 HEAD 从该提交创建补丁。现在,我有第二个存储库,其中包含一个与 hello.test 具有相同内容但以不同名称放置在不同目录中的文件:./blue/red/hi.test。如何将上述补丁应用到hi.test 文件?我试过git am --directory='blue/red' < patch_file,但这当然会抱怨文件的名称不同(我认为Git不在乎?)。我知道我可能可以编辑差异以应用于该特定文件,但我正在寻找命令解决方案。

【问题讨论】:

相关:***.com/q/3367254/1959808 【参考方案1】:

您可以使用git diff 创建补丁,然后使用patch 实用程序应用它,它允许您指定要应用差异的文件。

例如:

cd first-repo
git diff HEAD^ -- hello.test > ~/patch_file

cd ../second-repo
patch -p1 blue/red/hi.test ~/patch_file

【讨论】:

啊,不错,没想到。但是,有没有办法使用 Git 命令来做到这一点,以使提交数据(日期和时间、提交作者、提交消息)保持不变? 您可以使用amapply 做一些事情,但我找不到。如果您发现自己重复了很多更改,那么使用子模块或您选择的任何语言提供的共享代码可能会有更好的解决方案(例如,在 Ruby 中,您可以将重复的代码提取为 gem)。 这实际上与文档相关(源文件是 XML)。子模块并不是一个真正的选择,因为我必须在我们现有的基础设施中为它们提供强有力的理由。 在 Windows 上,可以使用 git-bash,它包含在 Git for Windows 中。 git-bash 包括几个 Unix 命令,包括 patch【参考方案2】:

使用执行此操作的脚本回答我自己的问题:https://github.com/mprpic/apply-patch-to-file

它不是手动修改补丁文件,而是提示用户输入目标文件,修改补丁,并将其应用于您当前所在的存储库。

【讨论】:

【参考方案3】:

有一个简单的解决方案,不涉及手动补丁编辑或外部脚本。

在第一个存储库中(这也可能导出一个提交范围,如果您只想选择一个提交,请使用-1):

git format-patch --relative <committish> --stdout > ~/patch

在第二个仓库中:

git am --directory blue/red/ ~/patch

除了在git format-patch 中使用--relative,另一种解决方案是在git am 中使用-p&lt;n&gt; 选项从补丁路径中删除n 目录,如answer to a similar question 中所述。

也可以在没有--stdout 的情况下运行git format-patch --relative &lt;committish&gt;,它会生成一组.patch 文件。然后可以使用git am --directory blue/red/ path/to/*.patch 将这些文件直接提供给git am

【讨论】:

这仍然依赖于文件名相同的事实,对吧? 应该注意--directory选项似乎要求你指定相对于repo root的目录的完整路径; --directory=./ 之类的东西,而 chdir'd 进入 repo 中的子目录将不起作用。 使用--3way 有助于does not exist in indexgit am --3way --directory (relative-path) (patch) 在两个命令中使用-k 键以不删除提交消息的第一行。 使用--3way 不仅有助于解决“索引中不存在”错误(正如@nobar 所指出的),而且还允许您干净地处理合并冲突。添加一个冲突块,然后可以解决,而不是保持冲突文件不变。【参考方案4】:

我知道这两个文件在你的情况下是完全一样的,因此补丁很可能会成功。

但是,如果您想将补丁应用于类似但不完全相同的文件,或者您想要进行交互式补丁,您将使用三向合并。

假设您修改了文件A,我们将A~1 表示为以前的版本,并且您想将A~1A 之间的差异应用到文件B

打开一个三向合并工具,比如Beyond Compare,左边面板的路径是A,中间面板是共同祖先所以路径是A~1,右边面板的路径是B。然后,下方面板显示了将A~1A 之间的差异应用于文件B 的结果。

下图说明了这个想法。

【讨论】:

【参考方案5】:

基于@georgebrock 的回答,这是我使用的解决方案:

首先,像往常一样创建补丁文件(例如git format-patch commitA..commitB)。

然后确保您的目标存储库是干净的(应该没有更改或未跟踪的文件)并像这样应用补丁:

cd second-repo
git am ~/00*.patch

对于每个补丁文件,您都会收到类似“错误:索引中不存在 XYZ”的错误。您现在可以手动应用此补丁文件:

patch --directory blue/red < ~/0001-*.patch
git add -a
git am --continue

您必须为每个补丁文件执行这三个步骤。

这将保留原始提交消息等,而无需任何特殊的git format-patch 命令或编辑补丁文件。

【讨论】:

好答案,我认为这是任何“非标准”补丁操作的最佳基础。我分三步做。 (1) 提交文本 - git format-patch -1 commitA --stdout &gt; thing.diff ; (2) 编辑补丁文件 直到它能满足我的需要; (3) 要提交的文本 git am --3way thing.diff 的优点是您可以接受补丁中干净应用的部分,并对不适用的部分使用git 的标准冲突解决流程t.【参考方案6】:

仅供参考:我最近在尝试从 Github 下载补丁并将其应用到本地文件时遇到问题(这是在新位置的“覆盖”)。

git am 不会应用补丁,因为文件“不在索引中”或“脏”。但是,我发现简单的patch 命令可以应用补丁。它确实提示我输入要修补的文件的名称。

无论如何都完成了工作......

【讨论】:

以上是关于如何将 Git 补丁应用于具有不同名称和路径的文件?的主要内容,如果未能解决你的问题,请参考以下文章

Git 补丁操作

如何将 git 补丁从一个存储库应用到另一个存储库?

什么是git版本控制中的补丁?

从 git 存储库创建补丁或差异文件并将其应用到另一个不同的 git 存储库

在 git 中使用 Windows 中具有相同名称但大小写不同的目录

Mercurial:将补丁应用于工作目录