Skip to content

Instantly share code, notes, and snippets.

@taikedz
Last active July 24, 2018 16:07
Show Gist options
  • Save taikedz/b1429565f84890965af3dc5f344771fe to your computer and use it in GitHub Desktop.
Save taikedz/b1429565f84890965af3dc5f344771fe to your computer and use it in GitHub Desktop.
Squash intermediate git commits (and a cherry-picking shorthand)

Squashing intermediate commits, cherry-picking

You cannot directly squash earlier commits whilst retaining later ones.

Instead you need to create a picking branch, do some reset operations, re-commit the intermediary changes, and cherry-pick over the relevant commits. You must start from a clean state - no modifications, no staged items, no untracked files. Working tree clean must appear in your git status.

Below, my-branch-name is the name of the branch you are on.

  1. Make a branch copy to perform the pick from - this also serves as a "backup" in case you need to abort squashing altogether/start again.
    • git branch pick/my-branch-name
  2. Hard-reset the changes you DO want to keep - say you want to preserve the last 2 commits:
    • git reset --hard HEAD~2
  3. Confirm that the commits to preserve still exist, and that your latest commits are the ones you want to squash
    • git log --all
    • (at this point, if you overshot, you can pull the changes back in and try again)
      • git pull . pick/my-branch-name
  4. Then, soft-reset the commits you want to squash, say the last 3 commits, and make a new single commit
    • git reset HEAD~3 ; git log --all
    • if all is ok, proceed:
    • git add .
    • git commit -m "new commit message"
  5. Now cherry-pick over the old commits from the pick branch
    • We use a couple of notations to specify the range from which to pick
      • relative commits notation with ~ to pick the second to last (my-branch-name~1) commit from the picking branch
      • We use the ^ to specify not to pick items from before the specified commit
      • we pick all the way up until the tip commit (my-branch-name itself)
    • git cherry-pick ^pick/my-branch-name~1 pick/my-branch-name
    • if you did it wrong, you can do git cherry-pick --abort here to bring your repository back to a clean state
    • git log --graph --all
  6. Picking is now done, your intermediaries are squashed and your extra commits are restored. You can now delete the picking branch if you are happy
    • git branch -D pick/my-branch-name
  7. If you need to scrap and try again, switch to the picking branch to use it as backup, delete your original branch, and then re-create it:
    • git checkout pick/my-branch-name
    • git branch -D my-branch-name
    • git branch my-branch-name
    • git checkout my-branch-name
    • git log
    • Then, return to step 2
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment