Assuming this is either not a public repository, or any other users of the repository are ok with significant rewriting, the most efficient way to accomplish this is with git filter-branch
. One of the possible filters is --parent-filter
, which allows you to change the parentage of specific commits, somewhat similarly to grafting or rebasing a portion of the tree, but since you can also pass the --all
option, you can accomplish the effect on multiple branches in one invocation. This could also be accomplished with a --commit-filter
; but that's a more general solution intended for changing other aspects of individual commits - not just the parents. You'd probably also want to use a --tag-name-filter cat
to move any tags in the portions of the tree being rewritten.
So the final command would look something like:
git filter-branch --parent-filter <somescript> --tag-name-filter cat -- --all
where <somescript>
is either properly quoted/escaped bash
code to replace A
with A'
for the B
commit (details on exactly how the information is provided to the script and what the results of the script should be can be found in git help filter-branch
), or the name of an actual shell script that accomplishes the same.
There is also some cleanup to be done afterwards - filter-branch
leaves your original branches in place, but with new names (refs/original/...
) so you can recover if something doesn't look right. There's plenty of information out there on how to remove dead branches once you're satisfied that filter-branch
did what you wanted, and re-packing your repository to recover the storage space, so I won't replicate that here...