能否将 Git 配置为始终将一个分支中的文件更改合并到另一个分支中的不同文件?

Can configure Git to always merge changes to a file in one branch to different files in another?

我在 GitHub 上维护一个自定义版本的 Ghost 主题。它从主 TryGhost/Casper 存储库中获取定期的更改流,这并不难跟踪。

有一件事困扰着我,它与我主题中的 custom-*.hbs 文件有关。每当 Ghost 更新 post.hbs 时,我必须记得将这些更改也合并到每个 custom-*.hbs 模板中。

有什么方法可以告诉 Git post.hbs 的更改必须始终合并到我这边的多个文件中?

可以在此处找到当前的 repo:

目前,我已经采取手动比较更改并将它们应用到相关文件的方法。

简短的回答是没有,这有点不幸。

当 Git 进行真正的合并时——我喜欢称之为 "merge as a verb"——Git 使用三个提交:merge base,Git 自行找到,以及两个 提示提交 。根据定义,其中一个提示提交总是 HEAD,另一个通常由某个分支名称标识:

          o--o--X   <-- you-are-here (HEAD)
         /
...--o--*   [merge base]
         \
          o--o--Y   <-- other-branch

像往常一样,所有三个提交都是所有文件的快照。 Git 执行合并——合并不同的变化 合并基础——实际上,运行:

git diff --find-renames <hash-of-*> <hash-of-X>   # what we changed
git diff --find-renames <hash-of-*> <hash-of-Y>   # what they changed

Git 然后梳理这些差异——由两个 diff 命令产生的变更集——并 配对 文件,因此它知道 file.ext 与我们的 file.ext 和他们的 and/or 相同。

如果重命名检测器检测到基础中的 file.ext 在我们的提交 X 中变成了 newname.ext,Git 知道它应该合并他们所做的更改到 file.ext 我们对 newname.ext-vs-file.ext 所做的更改,将最终结果存储在 newname.ext 中。但这是严格成对的。尽管 git diff 支持多个 "find copies" 选项,但 git merge 没有 "find copies" 选项。此外,没有 "break existing pairing" 选项(git diff 有一个,-B 有一个阈值,类似于重命名查找的 -M 和复制查找的 -C ): 如果合并基础和一个提示包含路径为 P 的文件,则该文件对在合并期间配对。如果合并基础和另一个提示包含路径为 P 的文件,则该文件对同样配对。

因此,如果您的合并基础包含 post.hbs 两个提示都包含 post.hbs,则配对严格为 post.hbs = post.hbs.

简短回答:不。但是您可以使用 git-merge-file 来实现这样的目的:

git merge-file <current-version> <common-ancestor> <other-version>

您可以使用第三个占位符文件创建一个“common-ancestor”,它应该包含预合并主文件:

git show HEAD~1:post.hbs > parent-post.hbs

然后 运行 以下将进行 3 向合并:

git merge-file custom-post.hbs parent-post.hbs post.hbs

为了使其自动化,您需要创建一个 post-merge githook,它在重新创建 common-ancestor 文件然后合并更改的常规合并之后运行。

如果 custom-* 文件与其非自定义对应文件相同,请考虑使用 symlinks