In one of my previous employers, we would make one commit per ticket. This seemed to go against the common wisdom “commit often”, but I noticed that it had several advantages.
The first advantage was that the feature was easy to roll back if needed. All you had to do was find the one single commit that represented an entire ticket (which could be a feature, bug, and etc.) and simply git revert
it. Compared to having multiple commits for one ticket, you would have to find all the commits and then revert all of them. I find reverting one single commit to be simpler.
The second advantage was that it was easier to code review. This could be entirely a personal preference, but I find one single commit much easier to review and easier on my eyes than following a sequence of commits for a single ticket. But again, this is a personal preference thing. Perhaps some people find it easier to understand what the programmer was thinking by following a sequence of commit messages, almost like reading a story of events that happened during the coding process for a single ticket.
I also think that people just don’t squash commits because they don’t know about it. After I started freelancing, I’ve noticed that squashing commits was one of those random git things that a lot of people didn’t know about. For example, I asked one other freelance developer to squash his commits in the pull request that he made and he didn’t know that was something he could do in git.
For those of you who don’t know how to squash commits, and would like to know, it’s very easy. All you have to do is take the number of previous commits that you would like to “squash” into one and run this in your terminal.
git rebase -i HEAD~{number of commits}
After you run that command, a default text editor set in your terminal will open up with the following content that looks like this.
Note: this is me squashing 3 commits into one so the command I ran would be
git rebase -i HEAD~3
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
pick b9197c3b1 first commit message pick 4fda19434 second commit message pick 3af3123fa third commit message # Rebase e69958e6b..4fda19434 onto e69958e6b (2 commands) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # d, drop = remove commit # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out |
From here, change the last two commit message’s “pick” statements into “squash” so that your editor looks like this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
pick b9197c3b1 first commit message squash 4fda19434 second commit message squash 3af3123fa third commit message # Rebase e69958e6b..4fda19434 onto e69958e6b (2 commands) # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # d, drop = remove commit # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # # However, if you remove everything, the rebase will be aborted. # # Note that empty commits are commented out |
Save and exit your editor and a new instance of your editor with the following content will open up.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
# This is a combination of 3 commits. # This is the 1st commit message: First commit message # This is the commit message #2: Second commit message # This is the commit message #3: Third commit message Please enter the commit message for your changes. Lines starting with '#' will be ignored, and an empty message aborts the commit. Author: Chris Jeon <chris0374@gmail.com> Date: Tues Aug 15 15:50:14 2016 -0500 interactive rebase in progress; onto 85dd27d6b Last commands done (3 commands done): squash b9197c3b1 second commit squash 4fda19434 third commit No commands remaining. You are currently rebasing branch 'squash-sample' on '85dd27d6b'. Changes to be committed: # Bunch of files to be committed will be listed here |
Now, you can just save this file and exit as it is and you’ll have squashed the three commits into one. If you want to write a new commit message, you can delete all of the three commit messages and write a new commit message like this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
NEW COMMIT MESSAGE!!! Please enter the commit message for your changes. Lines starting with '#' will be ignored, and an empty message aborts the commit. Author: Chris Jeon <chris0374@gmail.com> Date: Tues Aug 15 15:50:14 2016 -0500 interactive rebase in progress; onto 85dd27d6b Last commands done (3 commands done): squash b9197c3b1 second commit squash 4fda19434 third commit No commands remaining. You are currently rebasing branch 'squash-sample' on '85dd27d6b'. Changes to be committed: # Bunch of files to be committed will be listed here |
And then the commit message for the new one commit will be “NEW COMMIT MESSAGE!!!”.
As I mentioned, I prefer squashing commits especially when working on teams. This is all a personal preference of course and doesn’t mean that squashing is superior compared to multiple commit messages per ticket.
I thought I’d write this up since I’ve came across developers who weren’t aware of this feature in git.