gitghost

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


I'm maintaining a customized version of a Ghost theme on GitHub. it's taking in a regular stream of changes from the main TryGhost/Casper repo which isn't too hard to keep track of.

There is one thing that's bothering me and that has to do with the custom-*.hbs files in my theme. Whenever Ghost updates the post.hbs, I must remember to merge those changes into each custom-*.hbs template as well.

Is there a way I can tell Git that post.hbs's changes must always be merged into multiple files on my end?

The repo, as it is currently, can be found here:

For now, I've resorted to manually diffing the changes and applying them to the related files.


Solution

  • The short answer is no, which is a bit unfortunate.

    When Git is doing a true merge—a "merge as a verb", as I like to call it—Git works with three commits: the merge base, which Git finds on its own, and two tip commits. One of the tip commits is always HEAD, by definition, and the other is usually identified by some branch name:

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

    All three commits are snapshots of all files, as usual. Git performs the merge—combines the different changes since the merge base—by, in effect, running:

    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 then combs through these differences—the change-sets produced by the two diff commands—and pairs up files, so that it knows that file.ext in the base is the same file as file.ext in ours and/or in theirs.

    If the rename-detector detects that file.ext in the base has become newname.ext in our commit X, Git knows that it should combine the changes they made to file.ext to the changes we made to newname.ext-vs-file.ext, storing the final result in newname.ext. But this is strictly pairwise. Although git diff supports several "find copies" options, there is no "find copies" option to git merge. Furthermore, there is no "break existing pairing" option (git diff has one, -B with a threshold, similar to -M for rename-finding and -C for copy-finding): if the merge base and one tip contains a file whose path is P, that file-pair is paired for the duration of the merge. If the merge base and the other tip contains a file whose path is P, that file-pair is likewise paired.

    Hence, if your merge base contains post.hbs and both tips contain post.hbs, the pairing is strictly post.hbs = post.hbs.