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!
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
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.
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.
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.
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.
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
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
Force pushes:
git push --force
git push --force-with-lease
โ 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
โฐ Other posts
๐ Rails Helpers โ what are they and what are they used for?
Top comments (0)