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

Posted

技术标签:

【中文标题】如何将 git 补丁从一个存储库应用到另一个存储库?【英文标题】:How to apply a git patch from one repository to another? 【发布时间】:2010-10-30 05:36:46 【问题描述】:

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

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

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

主仓库:www.playdar.org/static/playdar.js 项目:playlick.com/lib/playdar.js

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

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

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

【问题讨论】:

类似:问题:***.com/questions/3367254/… 【参考方案1】:

如果无法手动编辑补丁文件或不可行,则可以使用标准选项(在git applygit format-patch 和 GNU patch 中提供)来完成。

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

    处理-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/'

【讨论】:

有机会做出这个最佳答案吗?这比手动编辑补丁文件要容易得多。 当然,这是一个更好/更简单的答案,尽管@araqnid 的答案仍然很高兴知道。 第一次尝试后调整目录相关,不用--directory:***.com/questions/24121709/…【参考方案2】:

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.js 更改为static/playdar.js,然后通过git am" 运行补丁

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

【讨论】:

稍后再访问此页面...这比之前建议子模块的“赢家”更好地回答了所提出的问题。【参考方案3】:

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

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

【讨论】:

嗯,阅读了子模块文档后,这听起来不像是“一种简单的方法”,尽管它可能是最健壮的。看起来我必须创建一个仅包含 playdar.js 文件的子模块,然后将其包含在其他两个项目中(我不希望 playlick.com 项目中的 www.playdar.org 中的所有其他内容)我可能只是手动求助老实说,现在编辑补丁文件。或者继续在两者之间复制粘贴。干杯。 这里有一个清晰透彻的教程和 git 子模块入门,供其他人偶然发现这个问题:book.git-scm.com/5_submodules.html【参考方案4】:

完成Henrik's answer,获得积分

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

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

【讨论】:

【参考方案5】:

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

[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 选项的文档似乎是 missing in some cases,但它似乎仍然可以工作(从 2.7.4 版开始)。

【讨论】:

【参考方案6】:

您可以添加一个新的遥控器并从中提取。 Article with details.

$ cd <path-to-repoB>
$ git remote add repoA <git-URL-for-repoA>
$ git pull repoA

【讨论】:

【参考方案7】:

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

cd to/main/project
mv .git .git_
cd to/sub/project
git apply patchname
cd -
mv .git_ .git

【讨论】:

以上是关于如何将 git 补丁从一个存储库应用到另一个存储库?的主要内容,如果未能解决你的问题,请参考以下文章

如何应用使用 git format-patch 生成的补丁?

如何从一个 Git 存储库迁移到另一个 Git 存储库?

sh 将子目录从一个git存储库移动到另一个git存储库的子目录,而不会丢失提交历史记录。

如何将Git存储库转移到另一个主分支

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

sh 在存储库外部应用git补丁