Git Squash - How to Combine Git Commits With Merge and Rebase
Git Squash - How to Combine Git Commits With Merge and Rebase

In this video I want to talk about one useful git feature which is squashing commits.

So squashing commit goes a lot in direction of differences between merge and rebase. So if you didn't see my video "Differences between merge and rebase" I highly recommend to check if first. I will post a link in the description. Just to sum up the previous video - always use merge and not rebase because it's save and do are not override git history. Which brings us to squashing.

So what is squash in git? It's a process when you take several commits and make single commit from them. The question is why do you need something like this? So normally when you develop some feature you created a feature branch from master and are working there. And you need to try and split your feature in logical chunks of code like for example implementing core, adding UI, using created component everywhere. And then for every local chunk we create a commit. Then it's easier for reviewer to check the PR by commits and not like a huge blop. But of course it's not always possible to do that. If you commited several times with not logical commit but just to commit your changes or you didn't plan chunks of your feature than probably you want to improve your commits or squash them into single commit.

Now the question is how to do that? It is possible to do git squash with merge and rebase. And they have exactly the same pros and cons like just using merge and rebase. Merge won't override history and rebase will.

But at the beginning I want to mention an easy of working for you with git. Just forget about squash and especially squash with rebase. I saw projects with both clean history and naming of commits and not so clean. Of course cleaner naming is better but people can live with both of them. Especially if you are not digging in git history too often.

If you still want to squash you commits I can recommend only doing squash commit with merge when you are merging your feature branch in the master. It is completely safe and it will just melt all your commits from feature in a single commit.

Let's try this out

So here I'm in master with no commit yet. Let's say that we create a first commit on master

const a = 'a'
git add .
git commit -m "First commit on master"

Now we want to start create our feature. Let's create a branch and do several commits there

git checkout -b other-feature
const b = 'b'
git add .
git commit -m "First commit on some feature"
const c = 'c'
git add .
git commit -m "Second commit on some feature"

So now we have 2 commits on our feature branch. Let' say that this commit were named bad and it can of course be that you have like 10-20 bad commits. So we want now to merge our feature in master but squash all commits in one commit

git checkout master
git merge --squash other-branch

As you can see git merge didn't create a commit for us like it normally does and all changes that we made on feature branch are now not commited and just handing for us to commit them.

So we can simply now commit all our changes that we made on feature branch with single commit like

git add .
git commit -m "Implemented other-feature"

And this is it with merge. It's completely safe because you don't change git history you simply transformed all commits from feature branch to single commit with squash.

So if you want to do squash then this is the only way how I can recommend do it.

Now let's look on rebase variant of squashing. As you know from previous video I'm against using rebase at all because it can go bad really fast. The main problem as always that it changes our git history and mostly you will find recommendations to do it only locally before you push your changes in remote.

So let's just in the state where we have 2 commits on feature branch and we finished our feature and we want to squash all this commits together.

What we want to do now is an interactive rebase. It's how you squash commits in single commit with rebase. And the first problem here that you can squash not all commits in feature but just for amount the you need. But let's say that we want to squash all of them. For this we need to find commit ID starting from which we want to do squash. We can do it with git log command.

git rebase -i COMMIT_ID

As you can see git rebase opens an editor for us. Usually it will be vim if it's not configured to other editor. So here you can see our commits that we rebasing on the top with word pick on the left. At the bottom there is lots of comments about possibilities what we can do with this commits. What we want to do is mark all commits except the one that we want to squash with word squash. And we just leave 1 commit with word pick. We can also reoder commits here if we need to and if you will remove some commit from here it will be lost completely.

So we want to mark one commit with pick and other with squash. If we have 10 more commits that we will mark all of them except one with squash.

Now we simply need to close the editor.

As you can see rebase opened for us new window where we can write some the title and the body of our new commit. The commented out code won't do anything.

So let's just write single title here "Implemented other feature" and close the editor. As you can see now we simply have only 1 commit so all our commits on the branch were squashed in this simply commit. It's important to mention that rebase changed the history. Which means if previously you already pushed your commits in github for example then now your history differs and you need to push with force in order to override history completely.

Now to bring our squashed feature to master we can use rebase or merge in this case it doesn't matter anymore because we have only a single commit.

git merge some-feature

As you can see we have the same output with single commit in master now.

So as you can see there are 2 ways of squashing commits. So simplify everything I simply recommend you to forget about squash and just merge what you have. Of course if you commits are logical chunks of code is always good. If you want to use squash I recommend to stick with merge command and not use rebase because it can lead to difficult to fix problems with git history.

And actually a have a course about git where I'm teaching you everything that you need to know in everyday work with git. I will link it in the description below as well as my other courses.