Most methods will be somewhat painful. There's a moderately painless version using git filter-branch , except that the filter branch itself is painful. :-) (You have to filter the commit F and G and write a commit filter that replaces the new parents you want for F' , and allow filter branching operations to replace the original word for G )
I think the simplest method that does not resort to low level commands is to simply create a new merge and then rebase G to the new merge. The new merge may have conflicts, but we don't care, we just want to take the old merge tree, which we can do as follows:
$ git checkout <sha1>
In the first checkout you will be taken to a separate HEAD with one SHA-1, merge --no-commit will start the merge process with another SHA-1, git rm -rf . throws the merged tree and any conflicts, and git checkout <id> -- . fills the index and the work tree from the previous merge. The final git commit creates a F' merge with the same tree as the F merge, but with different parents.
At this point (still with HEAD disconnected) you can reinstall (or cherry) commit G (or many commits G ), and then force your branch to indicate the tip of the new graph. I would suggest using git rebase ... --onto HEAD , but I have not tested this with HEAD disconnected and there is at least one of the ways this might go wrong (allowing HEAD on the identifier is too late).
The low level git commit-tree command can be even simpler. Andrew C wrote the correct command in a comment , although you need to specify the branch name git update-ref . [Edit: maybe not quite right, the two parents you want are D and E , not D and B Again, first put the one you want as the first parent.]
The advantage (?) Of using more familiar commands is that, well, they are more familiar.
torek source share