89

我有两个存储库,一个是库的主存储库,另一个是使用该库的项目。

如果我对从属项目中的 进行修复,我想要一种简单的方法将该补丁应用回上游。

该文件的位置在每个存储库中都不同。

  • 主要回购:www.playdar.org/static/playdar.js
  • 项目:playlick.com/lib/playdar.js

我尝试git format-patch -- lib/playdar.js在 playlick 项目上使用,然后git am在主 playdar repo 上使用,但补丁文件中的不同文件位置引发了错误。

有没有一种简单的方法可以将补丁从给定文件上的给定提交应用到其他地方的另一个任意文件?

对于奖励积分,如果您要应用补丁的文件不在 git 存储库中怎么办?

4

7 回答 7

127

如果手动编辑补丁文件是不可能的或不可行的,这可以使用标准选项(在 和 GNU 中可用git applygit format-patch来完成patch

  1. -p<n>从补丁中的路径中删除n前导目录。

  2. 在处理之后-p,在应用之前添加到--directory=<root>补丁root中的每个路径。

例子

因此,对于您的示例,要获取最初打开的补丁static/playdar.js并将其应用于lib/playdar.js,您将运行:

$ cat patch_file | git am     \ 
          -p1                 \ # remove 1 leading directory ('static/')
         --directory='lib/'     # prepend 'lib/'
于 2012-06-29T14:43:36.807 回答
40

生成的补丁git format-patch只是一个文本文件——您可以编辑差异标头,以便它修改不同的路径。

因此,例如它会产生这样的东西:

diff --git a/lib/playdar.js b/lib/playdar.js
index 1234567..89abcde
-- a/lib/playdar.js
++ b/lib/playdar.js

您所要做的就是更改lib/playdar.jsstatic/playdar.js然后运行补丁git am"

对于没有git--- 但在这种情况下不使用 等选项运行format-patch-M生成-C重命名补丁的人,该补丁应该可以被标准 GNU 补丁实用程序读取,因为对它们的支持并不普遍。

于 2009-05-31T12:53:01.060 回答
4

假设这两个项目都是 git 项目,听起来子模块非常适合您。这允许一个 git 项目动态链接到另一个 git 项目,本质上是在另一个 git 存储库中烘焙一个 git 存储库,两者都有自己不同的生命。

换句话说,将“main repo”添加为“project”中的子模块。每当您在“主仓库”中提交/推送新内容时,您只需git pull将它们返回“项目”。

于 2009-05-31T11:48:17.947 回答
2

完成Henrik 的回答,并获得奖励积分

如果要应用补丁的文件不在 git 存储库中怎么办?

如果您有权访问来自 git 存储库的补丁的候选文件的目录,则可以首先将该目录/文件树转换为 git 存储库本身!(' git init':一个 git 存储库毕竟只是根目录中的一个 .git)。
然后,您将该 repo 设置为您的主项目的子模块。

于 2009-05-31T12:01:06.360 回答
2

使用该--relative选项format-patch可以改进抽象(隐藏有关生成补丁的存储库的不相关详细信息)。

[repository-with-changes]
git format-patch --relative=(path-to-library) (base-commit-for-patch) ## 'HEAD~1'

我发现--3way应用补丁时需要该选项(以避免does not exist in index错误)——您的里程可能会有所不同。--directory=(...)仅当您的目标路径不是存储库的根目录时,才可能需要使用。

[repository-to-update]
git am --3way --directory=(path-to-library) (patch-file)

  • format-patch自“base”以来,每次提交到当前分支都会创建一个补丁文件。

  • 在某些情况下--relative似乎缺少该选项的文档,但它似乎仍然可以工作(从 2.7.4 版开始)。

于 2017-12-11T14:56:09.080 回答
1

您可以添加一个新的遥控器并从中提取。有细节的文章。

$ cd <path-to-repoB>
$ git remote add repoA <git-URL-for-repoA>
$ git pull repoA
于 2014-12-29T06:25:34.353 回答
1

您可以暂时删除(重命名)主存储库。

cd to/main/project
mv .git .git_
cd to/sub/project
git apply patchname
cd -
mv .git_ .git
于 2015-03-03T09:29:25.853 回答