We have 2 git repos, one of which we expose to a third party library where we want to share our changesets as part of the git history, but their filenames are slightly different.
Currently we have a shell script that will copy over all of the files and handle the renaming, however, this is not ideal because when we go to commit in the other repository, it goes in as one large commit (so it’s missing the changes, as well as the reasons for those changes).
An example of the type of stuff we do would be:
Let’s say in repo A (our source that we work in day to day) we have a structure like:
module-x/
module-x.js
In repo B (where we want to copy our commits into), the structure looks like this:
gallery-module-x/
gallery-module-x.js
(in addition, there are other scriptable changes in the content of the files as well).
Is there a way to either copy of the history and run the script on the files to sync them up (but keeping the content changes and commit message, so creating a new commit in the third party repo)?
I was thinking of setting up either a post-commit hook locally, or a post-receive hook on github, but wasn’t sure if it’s possible to do that, or if there’s a better way to do this.
Any advice? Thanks in advance,
Anything you do is going to be pretty ugly, since Git at a fundamental level knows what the filenames are supposed to be. A tree with different filenames has a different SHA1, so the commits do too, and nothing will ever match up. This means that there’s not really anything reasonable you can do on GitHub, since there’s a lot of history rewriting that has to take place.
There are two primary things you could try doing.
One: use
git filter-branchwith a tree or index filter to rewrite all of history in one repo, renaming the files. You can read the documentation or search online or here to find examples of that. There’s an example in the manpage that’s fairly close to your use case, the last one in the example section, which moves all files into a subdirectory, doing so in a way that’s basically equivalent to removing or adding a prefix. Your version might be something like:(The sed replacement pattern is where you need to be careful.) You’d want to run it in a fresh clone, to avoid actually rewriting the branches in your original repo.
If you’re working in both repositories, this will require a lot of careful work to stay in sync, avoiding mismatches between the two repos, and you’d have to do the opposite transformation to bring things back the other way. But if the exposed/shared one is read-only, then this option is wonderful; think of the filter-branch as a precursor to exporting. Save a script to do this, and all you’ll have to do is clone, filter-branch, and push.
Two: manually transfer patches. You can use
git format-patch <revision-range>to create patches, then do some automatic replacement of filenames in those patches, then apply them in the other repository. It’s ugly, but it does work.I suppose that you could trigger either of these things off of a post-commit hook locally, but they might be more time-consuming than you want, since you’ll probably commit often and want to move on immediately. One other option, which I assume you’ve already considered and dismissed for some reason, is to use your existing script, kicked off from a post-commit hook, to copy/rename files into the other repo, and immediately commit there. (One commit per commit, not one large commit per several commits.)