Search code examples
gitrebasecherry-pick

Rebase merge to have never happened


Due to (very odd) circumstances I now have a git repository with 2 roots. I would like to delete the merge that causes the second root to appear. Technically each of these "roots," is a commit with a parent of 0.

I want to get rid of the merge that causes there to be two roots.

I used git cherry-pick and that didn't work, it seems to not apply any changes.

To be clear I want a', b' and c' to all go away (they are broken copies of a, b and c caused by a bad rebase).

a <- b <- c \ / g <- h \ d -f origin/master a' <- b' <- c' / \ i <- j /


Solution

  • If communication or others' work already based off anything with d in its ancestry is a problem, consider just living with the two roots, if you like the rest of the commits they're pretty much consequence-free anyway.

    Do you want to dump the effect of the merge, or just the ancestry?

    If commit d contains changes you want to preserve, or contains no changes,

    echo `git rev-parse $d $d^` >.git/info/grafts
    git filter-branch -- --all
    rm .git/info/grafts
    

    will do it.

    If commit d contains changes you don't want to preserve, then you can just rebase the merge away with

    git rebase -p --onto $d^ $d..origin/master
    

    The $'s are shell variable syntax, substitute any reference you like for the named commits.

    Any history rewrite like these can have ripple effects on other commits based on (i.e. that can trace ancestry to) the rewritten one commits. So, afterwards, you'll need to force-push origin/master and have everyone else refetch and do any rebasing necessary if they've based their own work on any commit since c.