Introduction
Have you ever found yourself in a situation when you made a lot of commits with messages like fix
, 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?
Luckily, 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
cd
into it. - 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
dev
branch:
$ git checkout -b dev
- Run below script to mess up our git history. It will append character
a
to filea
inside the repository 10 times and commit each change.
./append_and_commit.sh
- 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
dev
branch to remote main.
$ git pull
Already up to date.
- create
new_dev
branch from main:
$ git checkout -b new_dev
Switched to a new branch 'new_dev'
- Show time:) Merge
dev
branch intonew_dev
branch. Note thatmerge --squash
is 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
a
file? 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
Final words
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. If you found this article useful, take a look at the disclaimer for information on how to thank me.
You may find below articles useful as well:
- Git Repository in Another Git RepositoryGit Repository in Another Git Repository
- GitLab Self-Hosted Runners Demo
- Clone Private Repositories in GitLab Pipelines
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)