Have you ever found yourself in a situation when you made a lot of commits with messages like
more fixes in the dev branch? I did. It could have been that you stayed truthful to keeping git commits as small as possible. However, this rule applies only if your small commits were fully complete and tested. Let’s be honest, such commits most probably weren’t. Apparently, you just wanted to finish this never-ending task just to get it done.
Eventually, if you are lucky and patient enough, all these fixes lead to some working code. Would you merge it master? You could, but all these commits won’t pass code review. They shouldn’t, as this would make main branch messy as well. No one will be willing to understand these commits. Moreover, no one should ever revert to these commits, because they don’t represent a stable state in a repository history. So, what should we do?
git merge --squash is the magic command which will help us to “squash” all these commits into one. The one we will merge to main branch.
While part 2 of Introduction into Kafka in Production is still in the works, I’d like to share how helpful
git merge --squash might be when we messed up our git history.
To get some context, click here to see a visual demo of how
git merge --squash works and read its documentation here.
Keep reading if you’d like to give it a try on a sample repository.
Firstly, we’ll simulate messing up our git history. Then, we’ll apply
git merge --squash to clean up the mess.
Let’s mess up our git history
- clone sample repo from my github and
- we are on main branch:
$ git status On branch main Your branch is up to date with 'origin/main'. nothing to commit, working tree clean
- let’s create and checkout new
$ git checkout -b dev
- Run below script to mess up our git history. It will append character
ainside the repository 10 times and commit each change.
- let’s inspect the mess we created:
$ git log -n 10 --pretty=oneline e8e0014f06eb7497079f8ab43b63cf86cd0b304a (HEAD -> dev) fix 1c001704ab177ac0fd3cc336756a8282c8379741 fix 2f1bce48d4569c606eb12d88ae5e74066727c048 fix 67094f12d25c1789f0952ee483bb0722c16258a1 fix ...
- resist the temptation to push these messy 10 commits to remote and merge to master.
Git merge squash it
We are just 4 steps from salvation. What would save us? Right, squashing all 10 commits into one with a meaningful commit message which we’ll merge to master.
- let’s go back to main branch:
$ git checkout main Switched to branch 'main' Your branch is up to date with 'origin/main'.
- Get changes merged to main branch by other developers while we were doing our numerous fixes. Of course, this is not needed in our demo. However, doing so in real life might save you from resolving merge conflicts when you merge your remote
devbranch to remote main.
$ git pull Already up to date.
new_devbranch from main:
$ git checkout -b new_dev Switched to a new branch 'new_dev'
- Show time:) Merge
new_devbranch. Note that
merge --squashis done using fast forward by default.
$ git merge --squash dev Updating e65d8ba..e8e0014 Fast-forward Squash commit -- not updating HEAD a | 10 ++++++++++ 1 file changed, 10 insertions(+)
- Did we merge all those messy commits? Of course not!
git log -n 1 --pretty=oneline e65d8ba0540c8496606e61452634e56c847c8a80 (HEAD -> new_dev, origin/main, origin/HEAD, main) added append and commit script
- Did we merge performed changes to
afile? Yes, of course:
$ git status On branch new_dev Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: a
- let’s commit this change with a meaningful commit message:
$ git commit -am "many many fixes, now it works, really" [new_dev 8878345] many many fixes, now it works, really 1 file changed, 10 insertions(+)
- push changes to remote:
$ git push --set-upstream origin new_dev ... To github.com:w7089/git_squash_example.git * [new branch] new_dev -> new_dev ...
- Now it’s safe to open pull request and merge to main. Do it on your github if you forked my sample repository.
- Let’s go back to main branch and pull merged changes from remote main:
$ git checkout main Switched to branch 'main' Your branch is up to date with 'origin/main'. $ git pull ... From github.com:w7089/git_squash_example e65d8ba..a60e3c4 main -> origin/main Updating e65d8ba..a60e3c4 Fast-forward a | 10 ++++++++++ 1 file changed, 10 insertions(+)
- Let’s inspect main branch history and notice our single commit.
$ git log -n 3 --pretty=oneline a60e3c49793d7d9c017c32d2e93efef89ee05157 (HEAD -> main, origin/main, origin/HEAD) Merge pull request #1 from w7089/new_dev 88783458b2cd0beffd82cb65e43178d02f93e5ab (origin/new_dev, new_dev) many many fixes e65d8ba0540c8496606e61452634e56c847c8a80 added append and commit script
Wow, this post turned out to be longer than I thought. And we discussed just one git command.
git merge --squash has been really a rare jam waiting to be discovered in my journey of git usage 🙂 Without a doubt, it deserved its own dedicated post.
Feel free to share and comment.
Bonus: Recommended Git courses on Pluralsight I learned from.
Sign up using this link to get exclusive discounts like 50% off your first month or 15% off an annual subscription)