DEV Community

Cover image for A Study on Git Rebase
Olivia Mattiazzo
Olivia Mattiazzo

Posted on

A Study on Git Rebase

It's been a while since I wanted to research and write about the difference between git push --force and git push --force-with-lease. Today, I started looking into these two commands and also thought: hmm, why not include an introduction to git rebase as well? After all, it's such a feared tool, surrounded by so many myths, and personally, I didn't know much about it—just that I need to use it. So, I decided to combine my curiosity with the opportunity to create a study on git rebase and share it here with everyone!

Merge, Squash or Rebase?


Conceptually, what is Git Rebase?

First, let me clarify that rebase is one of the methods available in Git for updating branches, along with merge (if there are others, let me know, because I can't remember 😅). When you create a feature branch—this special place where you'll start developing a new feature for a system—you do so from the latest commit of a main branch. The characteristic of rebase, unlike merge, is that it changes the base of your branch from one commit to another, making it appear as though you created your feature branch from a different, more recent starting point than the one where you initially started your work.

A bit confusing, right? Hold on, I'll try to clarify with a diagram.

A Git Rebase in 3 Acts

Act I - New Branch


Act I - New Branch

The person speaking here went ahead and created a new branch from the main branch of a project. The initial commit of my branch, which we’ll call branch-oli, is commit wap662, which includes everything from the main branch up to that point.

Act II - Updated branch


Act II - Updated branch

The next day, a colleague merged their feature branch, branch-do-colega, into the main branch. As a result, the main branch was updated, and its latest commit, which will serve as the base for any new feature branches, is now commit sus0sz. However, my branch, branch-oli, became outdated and needs to be updated with the latest changes from the main branch. I can do this in two ways: using git merge or git rebase. Today, I'll use rebase: in other words, I'll make branch-oli have sus0sz as its base commit.

Act III - Rebase done


Act III - Rebase done

Awesome! Our code is now fully updated.

So, what are the advantages of Git Rebase?

The most practical advantage of rebase is that it results in a cleaner merge of your feature branch into the main branch. The poetic advantage is this: the commits in the main branch are largely composed of merges from other branches. When these merges come with descriptive titles and are done with care, the commits in the main branch start telling the story of a system. Rebase helps make this story more linear, making it more coherent and easier to follow.

When it comes to tracking down which feature branch introduced a bug into the production codebase, having a tidy and organized commit history makes it much easier to find the culprit.

How is this done?

Git organizes this “story” by creating new commits from the existing ones and applying them to the base (which, in this case, is your feature branch). Although the branch may appear unchanged to us, it actually consists of completely new and different commits after the rebase.

Types of Git Rebase

There are two types of Git Rebase available for use, each with its own advantages and disadvantages.

Standard Git Rebase: When you run the rebase command without any additional flags, it will simply take all the new commits created in a branch and automatically add them in front of the new base commit of your feature branch. This process is straightforward and doesn’t require much thought or concern.

Interactive Git Rebase: This occurs when you include the -i flag with the rebase command in the console/terminal. Interactive rebase allows you to modify commits made during development, including splitting, removing, or reordering them.

With interactive rebase, you can focus on developing your feature without worrying about the commit messages or their order. You can make necessary changes as you go, and before merging into the main branch, you can tidy up the commit history using the -i flag.

I wanna break free videoclip


Leave the Cleanup for Later!

Main Differences Between Git Merge and Git Rebase

First and foremost, it’s important to note that both commands address the same issue: integrating code changes between branches.

The primary difference is that Git Merge brings in the new code independently and integrates it through a single commit into your feature branch. It is a non-destructive operation, meaning there's little risk of making unwanted changes to the branch you're working on.

However, Merge can also introduce extra commits beyond those you've created. If the main branch is very active and you need to perform multiple merges throughout the development of your feature, these extra commits can clutter the “history” of your branch.

On the other hand, Git Rebase rewrites the history of your project, as explained earlier. This is beneficial for clarity and a clean history but can have a downside: it becomes less clear when new changes were added to the feature branch, leading to less context compared to using Git Merge.

About Force Pushes During Git Rebase

Why do we need --force push during a rebase?

Git has a rule called the Fast-Forward Rule: essentially, it will reject any commit if the remote branch is not an "ancestor" of what's on your local branch. Rebase breaks this rule because it creates new commits and changes the base of the local branch, which is why we need to use force push to bypass it. The --force flag will completely ignore the existing history of the feature branch and replace it with what’s on your machine.

Difference Between --force and --force-with-lease

--force is a blunt instrument. If someone has made commits while you were doing the Git rebase locally, those changes will be lost forever. However, this can be circumvented with --force-with-lease, which I translate loosely as forceful with care: Git will refuse to update the branch if its state differs from what is expected.

A man playing with a cat


Force into the force push!

In other words, when using --force-with-lease, Git will first check if the remote version of your feature branch is the same as the one you rebased or if there are any changes beyond the “re-created” commits. If there are additional changes, such as commits made by another developer, the push will be rejected. If there are no additional changes, you can bypass the Fast-Forward Rule without major issues.

Main Commands Related to Git Rebase

To perform a rebase:

git rebase [-i] branch-name
Enter fullscreen mode Exit fullscreen mode

Note: The -i flag is optional and is used for interactive rebases, as explained in the definition above.

To continue with the changes made:

git rebase --skip
Enter fullscreen mode Exit fullscreen mode

Force pushes:

git push --force
git push --force-with-lease
Enter fullscreen mode Exit fullscreen mode

✔ Links consulted

📗git rebase – Atlassian Git Tutorial

📘Atualizando um branch com git rebase – Jessica Temporal

📙Git rebase: integrando alterações de uma branch em outra, por Daniela Araújo – BeTrybe Blog

📕Merging vs. Rebasing – Atlassian Git Tutorial

📗Git Force vs Force with Lease, por Mohammad-Ali A’Râbi

📘Essa resposta no Stack Overflow


📩 A Last Message

Did you like the text? Do you have anything to add? Any constructive criticism? Feedback? Suggestions? Requests? Feel free to contact me via email (oli.pmatt@gmail.com), LinkedIn (/in/oliviamattiazzo) or through the comments section below! I’d be delighted to chat with you! ✨

You can also check the original post (in PT-BR) at my blog: oliviamattiazzo.dev

ko-fi


⏰ Other posts

💎 Rails Helpers – what are they and what are they used for?

💎 Super-helpful gem: syntax_suggest

Top comments (0)