Search code examples
gitgithubgit-lfs

Obliterate entire chain of commits from git history?


I have a very odd problem. After some misadventure with trying to migrate to Github's Large File Store and a botched attempt to migrate away from it, I now have a very messed-up git topology that looks like this:

A  - B  - C - D - E - F 
            /
A' - B' - C'

Now, C is exactly the same as C', B is exactly the same as B', and so on all the way back to the initial commit. If I do "git log", I essentially see duplicate commits for everything before D. D itself is an empty merge.

Is there a way to completely delete A', B', and C', so that my history looks like this?

A - B - C - E - F

Solution

  • Given that D introduces no changes, there are several ways you could do it.

    A rebase will work (as Schwern suggests). "Reparenting" would also work.

    Because rebase is "more familiar", I think some people might prefer that approach. On the other hand, there are some cases where a rebase becomes complicated on could introduce errors; for that reason, I prefer reparenting in cases where the two are expected to be the same.

    Assuming the history you've shown is the history of the master branch (and that nothing from D onward is reachable from any other branch), then the rebase would be

    git rebase --onto C D master
    

    replacing C and D with expressions that resolve the the corresponding commits (i.e. commit ID, or something like master~3 for C in the history diagram you showed).

    Note that I used the branch name, rather than a commit ID or other expression, to identify F. This way the rebase operation will move the branch automatically.

    If there are merges after D (even if they all collapse back down to a single still-current branch), or if there are multiple branches pointing into the history that you're moving, those are the most obvious cases where you might consider reparenting instead.

    In that case, you'd use git filter-branch. There are several ways to do it; see the git filter-branch docs (https://git-scm.com/docs/git-filter-branch) under parent-filter; there are examples that show specifically how to do a re-parenting of a commit.