I've got a git branch B
that's about 100 commits ahead of its ancestor A
. For each of those 100 commits, I'd like to run a script that:
- Runs an existing script
edit.sh
that makes about a thousand automated search-and-replace edits to one source file. - Appends the SHA of the original commit to the commit message of the rebased commit.
Other than those two automated steps, I don't want to make any changes during the rebase.
I could do this manually via git rebase -i
running the script and rewording the commit message 100 times, but what's a good way to automate the whole thing? (Without manual commands or editing for each of those 100 commits.)
I do need to keep all 100 commits in the history, though, because my branch isn't a feature branch. Instead, our repo is a fork of another repo and my branch is catching our fork up to upstream. It's very helpful to be able to show each upstream commit in the history of my fork, even if the content is a little different. But first I need to modify those commits to match the changes in our fork!
Note that we want to keep a linear history in our forked repo, so we're rebasing instead of using merge commits. So far we've been doing this via git rebase --onto
which has been working pretty well for all files except one file that's had so many changes in our fork that handling merge conflicts during its rebase is a huge pain.
I just merged a PR in the upstream repo that will make the problematic file much more similar to our fork. The changes in that PR were automated via this script. I verified that rebasing that file just got a lot easier. But in the meantime I've got ~100 commits to port (aka git rebase --onto
) from upstream=>fork until fork catches up with that PR in upstream.
So what I'm trying to do here is to create a local branch with 100 new commits that are the same as upstream's last 100 commits, except in each commit I rewrite the problematic file in those commits using the same script I used to create the upstream PR. Then I can do an interactive rebase against that temporary local branch, and have a much easier time handling the merge conflicts.
More info (don't need to read this)
BTW, here's more context about why we're doing this:
I'm one of the maintainers of two open-source repos: a JavaScript repo tc39/proposal-temporal and a TypeScript port of that repo: js-temporal/temporal-polyfill.
The JS repo is the "main" repo for our team: changes originate there, and are subsequently ported over to the TS repo. Ideally it could be done in the reverse order so we could just automate the TS=>JS step, but the repo is a proposal for making a change to JavaScript itself. The ECMA TC39 standards committee that owns the JavaScript spec would frown upon the reference polyfill for a JavaScript feature being written in TypeScript. :-) So we're stuck maintaining two polyfills: a JavaScript one for the standards committee, and a TypeScript one for production use.
For the most part this process works OK: the TS repo has the JS repo set up as a remote, and we fetch commits from the JS repo and use git rebase --onto
to replay commits onto the TS repo. (We actually use some cool tools written by one of the maintainers to make this rebasing easier.)
If we can get through porting these 100 commits, then maintaining this fork will be much easier in the future!