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


80

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

如果我对从属项目中的进行了修复,则希望有一种简单的方法将该修补程序应用回上游。

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

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

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

是否有一种简便的方法将补丁从给定文件上的给定提交应用于其他位置的另一个任意文件?

为了获得加分,如果要将补丁应用到的文件不在git存储库中怎么办?


Answers:


116

如果手动编辑补丁文件是问题或不可行的了,这可以用标准的选项(可以在做git applygit format-patch和GNU 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/'

1
有机会做出这个最佳答案吗?这比手动编辑补丁文件要容易得多。
weston

当然,这是一个更好/更轻松的答案,尽管@araqnid的答案仍然很不错。
James Wheare

有关调整后的目录首先尝试无--directorystackoverflow.com/questions/24121709/...
扬FILIPPIDIS

38

由产生的补丁git format-patch只是一个文本文件-您可以编辑diff标题,以便修改其他路径。

因此,例如,它将产生以下内容:

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"

这个补丁应该是标准的GNU补丁程序为没有谁的人可读git---但不运行format-patch-M-C等选项,在这种情况下产生的重命名的补丁,因为对他们的支持是不具有普遍性。


1
稍后再访问此页面…与先前建议子模块的“优胜者”相比,这是对所提出问题的更好回答。
James Wheare

4

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

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


嗯,通读了子模块文档,这听起来似乎不是“一种简单的方法”,尽管它可能是最可靠的。看来我必须创建一个仅包含playdar.js文件的子模块,然后将其包含在其他两个项目中(我不希望www.playdar.orgplaylick.com项目中的其他内容)我现在可能只是手动编辑补丁文件。或继续在两者之间复制粘贴。干杯。
James Wheare 09年

这是一个清晰,透彻的教程,适用于遇到此问题的其他人入门git submodule:book.git-scm.com/5_submodules.html
James Wheare

2

完成Henrik的答案,并获得加分

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

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


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版开始)。



1

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.