6

How to Use Git Rebase to Squash a Sequence of Commits to a New Base Commit

 3 years ago
source link: https://hackernoon.com/how-to-use-git-rebase-to-squash-a-sequence-of-commits-to-a-new-base-commit-wf6c3522
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

How to Use Git Rebase to Squash a Sequence of Commits to a New Base Commit

May 4th 2021 new story
10
heart.pngheart.pngheart.pngheart.png
light.pnglight.pnglight.pnglight.png
boat.pngboat.pngboat.pngboat.png
money.pngmoney.pngmoney.pngmoney.png

@mralxAlex Ferreira

Front End Web Developer @hanko.io and owner of a cat named Ubuntu

What is a rebase? šŸ“š

Rebasing is one of the two Git processes of integrating changes from one branch to another.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

WhileĀ mergingĀ always moves a branch forward in history by simply adding a new commit representing each branch integration,Ā rebasingĀ can be much more powerful (and dangerous) as it allows us to rewrite history.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Why do we rebase? šŸ§

Rebasing is the process ofĀ movingĀ orĀ combining (i.e. squashing) a sequence of commitsĀ to a new base commit.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Imagine youā€™re working on a feature branch and after some time you realise theĀ mainĀ (aka "master") branch has been updated by someone else's code. This means your branch has now diverged from theĀ main branch. At some point, you will want to include said changes in your feature branch. A common way of doing this would be to simply do aĀ git pullĀ from mainĀ which would add aĀ merge commitĀ to your feature branch.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

The issues with this method can be:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
  • Merge commits
    Ā can be very vague, providing very little information in the git tree which makes debugging a much harder task
  • Updating a branch ā€” byĀ 
    pulling/Ā merging
    Ā - multiple times can result in a git history similar to this:

Reading this history provides very little (if any) information on what changes have been made to the project.

The goal of rebasing is to keep a clean, clear project history. So instead of pulling theĀ 

main
Ā changes and add a merge commit we can tell our branch to move its commits to the top of the latest changes
0 reactions
heart.png
light.png
money.png
thumbs-down.png

Feature branchĀ JIRA-123Ā is being rebased to the top of the master branch

By rebasing our feature branch to the top of theĀ 

main
Ā branch, we keep all the changes and commits we made unaltered while getting the latest mainĀ 
updates
. In order to achieve this, we can execute the following commandĀ while in our feature branch:
0 reactions
heart.png
light.png
money.png
thumbs-down.png
$ git rebase main

This will start the rebase process. If no conflicts are found you should see a success message and your feature branch is now up-to-date with theĀ mainĀ branch and we're one step closer to having a project history similar to this:

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Interactive rebase šŸ”¬

Interactive rebasing brings the power of rebasing to a whole new level! It allows us to interactively change multiple commits in different ways.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

You can start an interactive rebase by executing a rebase command followed by theĀ -iĀ parameter and the commit we want to modify:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
$ git rebase -i <commit hash | HEAD position>

Interactive rebase CLI showing the three last commits and always in order from oldest (top) to newest (bottom)

We can tell just by looking at the list of commands displayed in the CLI how powerful this tool can be! We can edit commits, squash them, remove them, amend them and so much more. We can even permanently change the commit order!

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Squashing

SquashingĀ allows us to specify which commits we want to combine in order to help maintain clean history.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Does something like this look familiar?

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Well, if you like committing a lot while you work you probably donā€™t like thinking about being super descriptive on every single commit message. Squashing can be extremely helpful in these situations because starting an interactive rebase you can then tell git which commits will be ā€œmergedā€ into one (or more) and then edit its commit message.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Keep in mind that we must always squash a commit ā€œintoā€ another one.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

So say we have 6 commits and we think only two of them are relevant we could squash the other 4 like:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
$ git rebase -i HEAD~6

ā€œsā€ is simply a shorthand name for ā€œsquashā€

In this case weā€™re saying weā€™d like to merge commits 2ā€“5 and include them in the first one (Ā 77497f5) and keep the last commit as-is.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Next git will rebase each commit to their new base (Ā 77497f5) and if there are no conflicts, you'll be able to change their final commit messages, and voila! Only 2 commits total!

0 reactions
heart.png
light.png
money.png
thumbs-down.png

What could go wrong? šŸ˜‡

Conflicts

Similarly to what happens with aĀ Git merge, updating a branch with another can result in code conflicts.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

A big difference in rebase conflicts is that weā€™re not dealing with oneĀ merge commitĀ but with (possibly) multiple commits being moved.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

This means rebase conflict solving is an iterative process that goes through each commit being rebased.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

In a feature branch with two commits, if a conflict is found while rebasingĀ commit AĀ we fix it, tell git to continue the process to the next commit, fix the new conflicts onĀ commit BĀ and only then weā€™ll be done

Pushing local branch after rebasing

Rebasing a local feature branch meansĀ weā€™re rewriting history, so what this actually means is that weā€™re not cherry-picking the feature branch commits to the new base. Although visually everything looks the same, Git creates new commits (with new hashes) on the targeted branch.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

This means whenever we try simply pushing our changes to our remote repo we get an error stating the local and remote branches have diverged.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

To fix this problem itā€™s good practice toĀ pushĀ using theĀ --force-with-leaseĀ parameter.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

You can checkĀ -force vs -force with leaseĀ to learn more about this.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

ā€œI think I made a mistakeā€

Have you heard of the beautiful command:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
$ git reflog

ReflogĀ allows us to check every change we did to our local branch. Running the command will return something like this:

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Reflog output showing the last 3 actions

In this case, if Iā€™d like to go back before I ever did the rebase I could jump back toĀ HEAD~2Ā or using its hash instead:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
$ git checkout 682c215

At this point, Iā€™m in the past and can undo the mistakes Iā€™d made before. Time travel!! šŸŽšŸ”„

0 reactions
heart.png
light.png
money.png
thumbs-down.png

If things get out of control

At any point in our interactive rebase if things get too messy and we no longer know how to fix them, we can always abort the whole process in the terminal and the interactive rebase will be canceled completely:

0 reactions
heart.png
light.png
money.png
thumbs-down.png
$ git rebase ā€” abort

Conclusion

As you can tell rebase can be used for a lot of different purposes, especially using the interactive rebase functionality. Hopefully, this article provides you with just enough to get started messing around with it.

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Donā€™t worry if you run into issues understanding some of the nuances of Git rebase. It has its learning curve and thatā€™s why I included some escape methods so you can go back and try again šŸ’Ŗ

0 reactions
heart.png
light.png
money.png
thumbs-down.png

Also published on Alex's Medium

0 reactions
heart.png
light.png
money.png
thumbs-down.png
10
heart.pngheart.pngheart.pngheart.png
light.pnglight.pnglight.pnglight.png
boat.pngboat.pngboat.pngboat.png
money.pngmoney.pngmoney.pngmoney.png
by Alex Ferreira @mralx. Front End Web Developer @hanko.io and owner of a cat named UbuntuRead my stories
Join Hacker Noon

Create your free account to unlock your custom reading experience.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK