Squashing commits is used to combine multiple commits into a single, larger commit.
In an ideal world code changes would only be done in short lived feature branches. The reality is we often need to share new snippets with others in a feature branch prior to merging into a release branch, or you find yourself forced to push multiple changes to branch while troubleshooting a pipeline issue.
All of these extraneous commits clutter your repository with noise, making it difficult to identity actual features in your code. Squashing allows you to rebase multiple commits into a single, larger commit, with the goal of not polluting your git log.
Rebase Squashing Commits
Squashing commits is the process of rebasing your repository. There a few methods to rebase squash your git history.
Rebasing can be done interactively, which is to say with a temporary file loaded into your shell’s default text editor. This is by and far the most recommend way of rebasing, as you can visually see exactly what you are attempting to accomplish. Rebasing will occur after the temporary file is saved. If no syntax errors are detected and the rebase completes successfully, the file will be deleted.
The two most common methods of rebasing are:
- Rebase from HEAD to an
xnumber of commits behind
- Rebase from a commit ID
To rebase an
x number of commits from
HEAD, you would use the following command syntax with git.
git rebase -i HEAD~[NUMBER OF COMMITS]
Alternatively, the second common method is to specify the commit ID you want to rebase from.
git rebase -i [COMMIT ID]
-i flag instructs Git to perform the rebase interactively.
git rebase -i HEAD~10, you are rebasing from
HEADScommit ID through to the previous 9 commits.
An interactive rebase will open your default text editor with contents similar to the following. All commits selected will be listed with a command (
pick), its commit ID, and the log text.
pick cac1790 Add ansible v2.10.0 released pick 524c030 Add using-unvault-to-read pick 41532d5 Create FUNDING.yml pick f4ae04d Add delete git branches pick 602781a Add git-branch-cheat-sheet pick 2782c19 Fix typos and grammar pick 02164c7 Remove old files pick 10468a4 Add kubernetes-v1.18.7-release pick 9341aa0 add set-default-kubernetes-namespace pick 1dc377e Add how-to-deploy-lamp-on-google-cloud-compute # Rebase ffbe8cb..1dc377e onto 10468a4 (10 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 <commit> = like "squash", but discard this commit's log message # 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. # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST.
The two primary commands you will use when squashing your commits are
fixup. The difference between these two is the former retains your log message, while the latter discards the log message.
Squash last 10 from head
head is the current position. To squash the ten most recent commits from head into a single commit, for example, you would rebase with
git rebase -i HEAD~10
To squash commits replace command
pick in front of each commit your want squashed with
squash cac1790 CLDY-1000: Finally! squash 524c030 CLDY-1000: Nope, not yet. More bugs. squash 41532d5 CLDY-1000: I think that's it! squash f4ae04d CLDY-1000: Bug fix again squash 602781a CLDY-1000: Bug fix squash 2782c19 CLDY-1000: Bad code. Who approved this?! squash 02164c7 CLDY-1000: Fixed text alignment squash 10468a4 CLDY-1000: More typos... squash 9341aa0 CLDY-1000: typo fixed pick 1dc377e CLDY-1000: New user profile
When you save your changes and exit the text editor, git will apply the desired commands onto your history. Notice how the first 9 commits have a
squash command, while the last commit remains as
pick. This instructs git to squash the first 9 commits into the last commit.
Squashing from Commit ID
Each commit is logged with a unique identifier, the commit ID. To squash all commits from your current HEAD to a specific commit, we can rebase using a commit ID.
git rebase -i 10468a4a06659311f55d2573a20437922b24c912
Rebase Fixup Commits
Squashing and fixup are very similar methods of combining commits. The difference is when a fixup is selected the log text for each commit is not retained. This is more useful when you have extraneous commits due to troubleshooting, for example. It’s unlikely you will want or need to retain these messages.
fixup cac1790 CLDY-1000: Finally! fixup 524c030 CLDY-1000: Nope, not yet. More bugs. fixup 41532d5 CLDY-1000: I think that's it! fixup f4ae04d CLDY-1000: Bug fix again fixup 602781a CLDY-1000: Bug fix fixup 2782c19 CLDY-1000: Bad code. Who approved this?! fixup 02164c7 CLDY-1000: Fixed text alignment fixup 10468a4 CLDY-1000: More typos... fixup 9341aa0 CLDY-1000: typo fixed pick 1dc377e CLDY-1000: New user profile
As with squashes, all commits from
9341aa0 will be merged into
1dc377e CLDY-1000: New user profile.