How can I split up a Git commit buried in history? How can I split up a Git commit buried in history? git git

How can I split up a Git commit buried in history?


There is a guide to splitting commits in the rebase manpage. The quick summary is:

  • Perform an interactive rebase including the target commit (e.g. git rebase -i <commit-to-split>^ branch) and mark it to be edited.

  • When the rebase reaches that commit, use git reset HEAD^ to reset to before the commit, but keep your work tree intact.

  • Incrementally add changes and commit them, making as many commits as desired. add -p can be useful to add only some of the changes in a given file. Use commit -c ORIG_HEAD if you want to re-use the original commit message for a certain commit.

  • If you want to test what you're committing (good idea!) use git stash to hide away the part you haven't committed (or stash --keep-index before you even commit it), test, then git stash pop to return the rest to the work tree. Keep making commits until you get all modifications committed, i.e. have a clean work tree.

  • Run git rebase --continue to proceed applying the commits after the now-split commit.


Here's how to do it with Magit.

Say commit ed417ae is the one you want to change; it contains two unrelated changes and is buried under one or more commits. Hit ll to show the log, and navigate to ed417ae:

initial log

Then hit r to open the rebase popup

rebase popup

and m to modify the commit at point.

Notice how the @ there is now on the commit you want to split – that means HEAD is now at that commit:

modifying a commit

We want to move HEAD to the parent, so navigate to the parent (47e18b3) and hit x (magit-reset-quickly, bound to o if you're using evil-magit) and enter to say "yes I meant commit at point". Your log should now look like:

log after resetting

Now, hit q to go to the regular Magit status, then use the regular unstage u command to unstage what doesn't go in the first commit, commit c the rest as usual, then stage and commit what goes in the second commit, and when done: hit r to open the rebase popup

rebase popup

and another r to continue, and you're done! ll now shows:

all done log


To split a commit <commit> and add the new commit before this one, and save the author date of <commit>, — the steps are following:

  1. Edit the commit before <commit>

    git rebase -i <commit>^^

    NB: perhaps it will be also needed to edit <commit> as well.

  2. Cherry pick <commit> into the index

    git cherry-pick -n <commit>
  3. Interactively reset unneeded changes from the index and reset the working tree

    git reset -p && git checkout-index -f -a

    As alternative, just stash unneeded changes interactively: git stash push -p -m "tmp other changes"

  4. Make other changes (if any) and create the new commit

    git commit -m "upd something" .

    Optionally, repeat the items 2-4 to add more intermediate commits.

  5. Continue rebasing

    git rebase --continue