【问题标题】:How can I generate/apply git patches only for commits that alter specific files如何仅为更改特定文件的提交生成/应用 git 补丁
【发布时间】:2013-04-04 06:23:39
【问题描述】:

我有两个 git 存储库,它们是彼此的分支,我需要偶尔将提交从一个导入另一个。

例如:

git-repo1 有这个目录结构:

repo1/project1/src

repo1/project2/src

git-repo2 具有以下目录结构:

repo2/src/

我想做的是进行一系列提交,并仅为更改特定子目录(例如repo1/project1/src)中文件的提交生成补丁,并忽略所有仅更改其他任何地方的文件的提交。

或者,为所有提交生成补丁,但仅在补丁更改特定目录中的文件时应用补丁。

我需要保留有关提交的元数据,因此使用 git diff 似乎不是一个可行的选择。

分叉的 git repos 之间的目录结构不同。

有没有直接的方法可以做到这一点?

更新1

我看到这个问题 (How to apply a git patch from one repository to another?) 是在处理不同的目录结构方面。

但是如果补丁提到修改根本不存在的文件怎么办?我想忽略这些变化。

【问题讨论】:

    标签: git git-diff git-patch


    【解决方案1】:

    git rev-list --reverseseries-- repo1/project1/src/ \
    | xargs -I@ git format-patch --stdout @^! >mystuff.patch

    series 中影响该子目录的提交发送到mystuff.patch

    那么,

    cat >mystuff.sed <<\EOD
    /^(From [0-9a-f]{40}|diff --git )/!{H;$!d}
    x
    /^From /b
    ${h;s,.*--,--,;x}
    \,^diff[^\n]* [ab]/repo1/project1/src/,!{$!d;x;b}
    ${p;x}
    EOD
    

    sed -Ef mystuff.sed mystuff.patch >justmystuff.patch
    

    将删除该目录之外的所有大块。你可以申请

    git am justmystuff.patch
    

    根据需要使用-pn--directory=new/path/to

    (编辑:EOD --> \EOD 所以上面的猫不会尝试替代)

    【讨论】:

    • 当使用命令“sed -rf mystuff.sed mystuff.patch >justmystuff.patch”我得到错误“sed:非法选项--r”你知道它可能是什么吗?跨度>
    • 改用-E-r 现在是一个历史拼写。已在答案中修复,谢谢。
    • 如果你能解释一下你的 sed 脚本就好了!
    • 用你最喜欢的文本编辑器搜索和替换也可以(嗯,至少对我有用)。我只是更改了路径并删除了引用子目录外文件的位。我没有触及提交哈希 - 我不知道上面的自动脚本是否像 @Neil 那样做。
    • 是否可以进行更改以使您还可以在其他特定文件或多个路径中保留创建和更改?例如,如果我有一个子目录sub-repo-a/,并且在该子目录的外部,我有一个名为.sub-repo-a.settings 的文件。我想保留影响这些路径的提交。
    【解决方案2】:

    如果两个存储库具有共同的历史记录(它们都来自同一个存储库,但演变不同),您可以使用cherry-picking 选择性地将提交从一个分支导入到另一个分支。

    创建一个带有两个远程的本地存储库(您的两个不同的存储库)

    在 repositoryA 中找到涉及某些文件的提交

     $ git checkout repoA/master
     $ git log sub/dir/ectory
     a34256f ...
    

    cherry-pick 那些提交到 repositoryB 的分支

     git checkout repoB/master
     git cherry-pick a34256f
    

    【讨论】:

    • 不,很遗憾他们没有共享历史。 :(
    【解决方案3】:

    我尝试了在此处和其他答案中找到的几种不同方法,但没有找到适合我的解决方案。这是我发现的。

    您可以给git format-patch 一个路径作为参数,以便它只为这些路径创建补丁。

    git format-patch HEAD --root $(git rev-list --max-parents=0 HEAD) --stdout -- repo1/project1/src/ > git.patch
    

    命令git rev-list --max-parents=0 HEAD 用于从存储库中获取初始提交引用

    应用补丁可以通过

    git am git.patch
    

    在我的例子中,我还想在应用补丁时跳过一个目录级别,因为我将整个目录从存储库移动到单独的存储库。 git am 使用的 git apply 有一个标志 -p&lt;n&gt;,它从差异路径中删除前导路径组件。默认值为 1,所以 git am -p2 git.patch 为我完成了这项工作。

    【讨论】:

      猜你喜欢
      • 2011-10-03
      • 1970-01-01
      • 1970-01-01
      • 2012-09-05
      • 2019-03-23
      • 1970-01-01
      • 2021-06-09
      • 2020-04-01
      • 1970-01-01
      相关资源
      最近更新 更多