Skip to content

Instantly share code, notes, and snippets.

@mswieboda
Last active November 21, 2024 16:51
Show Gist options
  • Save mswieboda/abdc347923639536b216fbbeeac1bea2 to your computer and use it in GitHub Desktop.
Save mswieboda/abdc347923639536b216fbbeeac1bea2 to your computer and use it in GitHub Desktop.
Git rebase to squash commits

Say you have a few commits on a branch and want to squash them all

(done via git log --oneline)

3cf1e45e Refactor
7bfc2e3b Cleanup
c203f2ba Did some fixes, adds tests
e28ebc36 Adds feature XYZ
d3ee6f4e Commit not to squash 

You want to:

  1. backup branch
  2. find commit before yours to use for rebase (d3ee6f4e)
  3. choose commits to squash using git rebase --interactive <commit-sha> and save
  4. edit commit message and save
  5. confirm with git log
  6. revert or remove temp branch
  7. push to remote

Backup branch

You can make a backup of your current branch, in case you do the rebase incorrectly with

git checkout -b tmp-branch

then git checkout - to go back to your branch. Once you get the hang of squashing, you probably don't need to do this step.

Find commit before yours to use for rebase

git rebase -i <commit-sha> takes a commit to start from, you'll want to do the commit before the one you want to sqaush to, or an earlier than that is fine too. Find a commit SHA via git log or you can use the shortcuts like head^, head^^^, head~5 etc to go backwards that way.

Choose commits to sqaush

You can squash these to one commit by using git rebase --interactive <commit-sha> or git rebase -i <commit-sha> interactive mode. You'll need to specify the SHA of the commit before, or a few before

git rebase --interactive d3ee6f4e

You will be presented in your editor the commits (sorted newest at the bottom) with pick in front. To squash the commits up to the next pick commit, change the pick to squash or s for short. There should be instructions at the bottom as a comments to help. Save and quit the editor.

ex of git rebase -i:

pick e28ebc36 Adds feature XYZ
pick c203f2ba Did some fixes, adds tests
pick 7bfc2e3b Cleanup
pick 3cf1e45e Refactor

# Rebase e28ebc36..e81b3049 onto e28ebc36 (3 commands)
#
# Commands:
# p, pick <commit> = use commit
# r, reword <commit> = use commit, but edit the commit message
# e, edit <commit> = use commit, but stop for amending
# s, squash <commit> = use commit, but meld into previous commit
# f, fixup [-C | -c] <commit> = like "squash" but keep only the previous
#                    commit's log message, unless -C is used, in which case
#                    keep only this commit's message; -c is same as -C but
#                    opens the editor
# x, exec <command> = run command (the rest of the line) using shell
# b, break = stop here (continue rebase later with 'git rebase --continue')
# d, drop <commit> = remove commit
# l, label <label> = label current HEAD with a name
# t, reset <label> = reset HEAD to a label
# m, merge [-C <commit> | -c <commit>] <label> [# <oneline>]
#         create a merge commit using the original merge commit's
#         message (or the oneline, if no original merge commit was
#         specified); use -c <commit> to reword the commit message
# u, update-ref <ref> = track a placeholder for the <ref> to be updated
#                       to this position in the new commits. The <ref> is
#                       updated at the end of the rebase
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#

you would want to switch the picks to squash or s except for the last commit of yours, keeping that as pick:

pick e28ebc36 Adds feature XYZ
s c203f2ba Did some fixes, adds tests
s 7bfc2e3b Cleanup
s 3cf1e45e Refactor

Then save the result (:wq if in the default vi editor).

Edit commit message

When you save the result, git will present an editor with a commit message similar to git commit, except all squashed commit messages will be there too, edit the entire commit message how you want and save. Sometimes it's easy to just prepend the previous commit messages with - or * like a bulleted list, but you're free to do whatever you'd like.

Confirm your changes

Confirm it's what you wanted with git log or however you'd like to see if it's how you wanted it.

Revert or remove temp branch

If everything looks good, you can remove the backed up temp branch you created via:

git branch -D <name>

If it's not how you wanted, and you want to go back to your original commits, you can use your temp branch:

git checkout <tmp-branch-name>
git branch -D <orig-branch-name>
git branch -m <orig-branch-name>

with git branch -m you will have renamed your backed up temp branch to the original branch name.

Pushing to remote

If you did the rebase and sqaushed the commits, we have changed git history, so if your old commits were on a remote branch, the history has changed, so you'll need to force push, via git push --force or git push -f next time. And if you reverted your temp branch, you might have to re-setup the upstream link via git push -u <branch-name> or git push --set-upstream <branch-name>

vi shortcuts for multi edit

vi shortcut for visual block mode, then delete, then insert mode:

  • CTRL-V for Visual Block mode, select lines of similar text pick for example
  • c for deleting the selections, and staying in insert mode
  • then type whatever you want, like s or squash, then ESC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment