Learning Center
Git

Git Rebase: How It Works and Why You Should Use It

16 Sep 2025
Hostman Team
Hostman Team

In the Git version control system, there are two ways to combine one branch with another, represented by different commands:

  • git merge. Commits from one branch are transferred into another by creating a merge commit.

  • git rebase. Commits from one branch are transferred into another branch while preserving the original order of changes.

Simply put: with git merge, the commits from one branch are “squashed” into one, while with git rebase they remain untouched, yet the branches are combined.

Thus, the git rebase command allows you to combine commits from both branches by forming a shared history of changes.

This guide will cover the git rebase command, which is responsible for rebasing commits (changes) from one branch to another.

All the examples shown used Git version 2.34.1, running on a Hostman server with the Ubuntu 22.04 operating system.

You can use these guides to install Git on your machine:

What is Git Rebase
Copy link

Git Rebase is a powerful Git command that is primarily used to integrate changes from one branch onto another by rewriting the commit history. Unlike git merge, which creates a new merge commit to combine branches and preserves the history of both, git rebase operates by moving or "replaying" a series of commits from one branch onto another. This process results in a linear history, making it appear as though the feature branch was developed directly off the most recent commit of the target branch, such as main or master. By doing so, it cleans up the commit history and removes unnecessary merge commits, resulting in a more streamlined project history.

How Git Rebase Works
Copy link

The best way to understand how rebasing works in Git is to look at an abstract repository consisting of several branches. At the same time, the rebasing operation should be considered step by step.

Creating Branches
Copy link

Let’s assume we created a repository with a single branch master, containing just one commit. The master branch looks like this:

master
  commit_1

Then, based on master, we created a new branch hypothesis, where we decided to test some features. In this new branch, we made several commits improving the code. The branch now looks like this:

hypothesis
  commit_4
  commit_3
  commit_2
  commit_1

Later, we added another commit to the master branch, urgently fixing a vulnerability. The master branch now looks like this:

master
  commit_5
  commit_1

Now our repository has two branches:

master
  commit_5
  commit_1

hypothesis
  commit_4
  commit_3
  commit_2
  commit_1

The master branch is the main branch, while hypothesis is secondary (derived). Later commits are listed above earlier ones, similar to the output of the git log command.

Merging Branches
Copy link

Let’s say we want to continue working on the feature we had previously moved into the separate hypothesis branch. However, this branch does not contain the critical vulnerability fix we made in master.

Therefore, we want to “synchronize” the state of hypothesis with master so that the fix commit also appears in the feature branch. In other words, we want the repository structure to look like this:

master
  commit_5
  commit_1

hypothesis
  commit_4
  commit_3
  commit_2
  commit_5
  commit_1

As you can see, the hypothesis branch now exactly repeats the history of master, even though it was originally created before commit_5. In other words, hypothesis now contains the history of both branches—its own and master.

To achieve this, we need to rebase using the git rebase command.

Afterward, the changes made in hypothesis can be merged into master using the classic git merge command, which creates a merge commit.

Then the repository structure will look like this:

master
  commit_merge
  commit_5
  commit_1

hypothesis
  commit_4
  commit_3
  commit_2
  commit_5
  commit_1

Moreover, running git merge after git rebase can reduce the likelihood of conflicts.

Practice: git rebase
Copy link

Now that we’ve covered the theoretical aspect of the git rebase command, we can move on to testing it in a real repository of an improvised project. The repository structure will repeat the earlier theoretical example.

Creating a Repository
Copy link

First, let’s create a separate directory to hold the repository:

mkdir rebase

Then move into it:

cd rebase

Now we can initialize the repository:

git init

In the console, a standard informational message should appear:

hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
...

And in the current directory, a hidden .git folder will appear, which you can view with the following command:

ls -a

The -a flag means all and allows viewing the file system in extended mode. Its contents will be:

.  ..  .git

Before making commits, we need to specify some basic user information.

First, the name:

git config --global user.name "NAME"

Then the email:

git config --global user.email "NAME@HOST.COM"

Populating the master Branch
Copy link

Using simple text files, we will simulate adding different functions to the project. Each new function will be represented as a separate commit.

Create a file for the first improvised function:

nano function_1

Fill it with the content:

Function 1

Now index the changes made in the repository:

git add .

Just in case, check the indexing status:

git status

In the console, the following message should appear, showing the indexed changes:

On branch master

No commits yet

Changes to be committed:
  (use "git rm --cached <file>..." to unstage)
        new file:   function_1

Now we can commit:

git commit -m "commit_1"

The console should display a message confirming the successful commit into master:

[master (root-commit) 4eb7cc3] commit_1
 1 file changed, 1 insertion(+)
 create mode 100644 function_1

Populating the hypothesis Branch
Copy link

Now let’s create a new branch called hypothesis:

git checkout -b hypothesis

The -b flag is necessary to switch immediately to the new branch.

The console will display a confirmation message:

Switched to a new branch 'hypothesis'

Next, we need to make three commits in sequence with three files, similar to master:

  • commit_2 with file function_2 and content: Function 2

  • commit_3 with file function_3 and content: Function 3

  • commit_4 with file function_4 and content: Function 4

If we then check the commit list:

git log --oneline

The console will display the following sequence:

d3efb82 (HEAD -> hypothesis) commit_4
c9f57b7 commit_3
c977f16 commit_2
4eb7cc3 (master) commit_1

Here, the --oneline flag is used to display commit information in a compressed single-line format.

Adding a Commit to the master Branch
Copy link

The last step is to add another commit to the main branch master. Let’s switch to it:

git checkout master

The console will confirm the switch:

Switched to branch 'master'

Now create another improvised function file:

nano function_5

With the following content:

Function 5

Next, index the changes:

git add .

And make the new commit:

git commit -m "commit_5"

If we check the current commit list:

git log --oneline

The master branch will now have two commits:

3df7a00 (HEAD -> master) commit_5
4eb7cc3 commit_1

Merging Branches with git rebase
Copy link

To perform rebasing, first you need to switch to the hypothesis branch:

git checkout hypothesis

And run the rebase:

git rebase master

After this, the console will display a message confirming a successful rebase:

Successfully rebased and updated refs/heads/hypothesis.

Now you can check the commit list:

git log --oneline

The console will show a list containing the commits of both branches in the original order:

8ecfd58 (HEAD -> hypothesis) commit_4
f715aba commit_3
ee47470 commit_2
3df7a00 (master) commit_5
4eb7cc3 commit_1

Now the hypothesis branch contains the complete history of the entire repository.

Resolving Conflicts
Copy link

Just like with git merge, when using the git rebase command, conflicts may occur that require manual resolution.

Let’s modify our repository in such a way that we artificially create a rebase conflict.

Create another file in the hypothesis branch:

nano conflict

And write the following text into it:

There must be a conflict here!

Index the changes:

git add .

And make another commit:

git commit -m "conflict_1"

Now switch to the master branch:

git checkout master

Create a similar file:

nano conflict

And fill it with the following content:

There must NOT be a conflict here!

Again, index the changes:

git add .

And make a commit:

git commit -m "conflict_2"

Reopen the created file:

nano conflict

And change its content to:

There definitely must NOT be a conflict here!

Again, index the changes:

git add .

And make another commit:

git commit -m "conflict_3"

Now switch back to the hypothesis branch:

git checkout hypothesis

And perform another rebase:

git rebase master

The console will display a conflict message:

Auto-merging conflict
CONFLICT (add/add): Merge conflict in conflict
error: could not apply 6003ed7... conflict_1
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
Could not apply 6003ed7... conflict_1

Git suggests editing the conflict file, indexing the changes with git add, and then continuing the rebase using the --continue flag.

That’s exactly what we will do:

nano conflict

The file will contain two conflicting versions wrapped in special markers:

<<<<<<< HEAD
There definitely must NOT be a conflict here!
=======
There must be a conflict here!
>>>>>>> 6003ed7 (conflict_1)

Our task is to remove the unnecessary parts and fill the file with a final version of arbitrary text:

There must absolutely definitely unanimously NOT be any conflict here!

Now index the changes:

git add .

And continue the rebase:

git rebase --continue

After this, the console will open a text editor suggesting you modify the original commit message of the commit where the conflict occurred:

conflict_1

# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# interactive rebase in progress; onto bd7aefc
# Last commands done (4 commands done):
#    pick 8ecfd58 commit_4
#    pick 6003ed7 conflict_1
# No commands remaining.
# You are currently rebasing branch 'hypothesis' on 'bd7aefc'.
#
# Changes to be committed:
#       modified:   conflict
#

The console will then display a message about the successful completion of the rebase process:

[detached HEAD 482db49] conflict_1
 1 file changed, 1 insertion(+), 1 deletion(-)
Successfully rebased and updated refs/heads/hypothesis.

Now if you check the commit list in the hypothesis branch:

git log --oneline

You will see the original sequence of all changes made:

482db49 (HEAD -> hypothesis) conflict_1
bd5d036 commit_4
407e245 commit_3
948b41c commit_2
bd7aefc (master) conflict_3
d98648d conflict_2
3df7a00 commit_5
4eb7cc3 commit_1

Notice that the commits conflict_2 and conflict_3, made in the master branch, appear in the history earlier than the conflict_1 commit. However, this applies to any commits made in the master branch.

Rebasing a Remote Repository
Copy link

In addition to working with local branches, rebasing can be done when pulling changes from a remote repository. To do this, you need to add the --rebase flag to the standard pull command:

git pull --rebase remote branch

Where:

  • remote is the remote repository

  • branch is the remote branch

Essentially, this pull configuration is equivalent to git rebase, except that the changes (commits) applied to the current branch are taken from the remote repository.

Key Benefits of Git Rebase
Copy link

  • Linearity 

The git rebase command makes it possible to form a fairly linear history of the target branch, consisting of sequentially made commits. Such a sequence without branching makes the history easier to perceive and understand.

  • Fewer conflicts 

Running git rebase beforehand can significantly reduce the likelihood of conflicts when merging branches with git merge. Conflicts are easier to resolve in sequential commits rather than in commits merged into a single merge commit. This is especially relevant when pushing branches to remote repositories.

Disadvantages of git rebase
Copy link

  • History modification 

Unlike merging, rebasing partially rewrites the history of the target branch, removing unnecessary history elements.

  • Risk of errors 

The ability to significantly restructure commit history can lead to irreversible errors in the repository. This means that some data may be permanently lost.

When to Use Git Rebase
Copy link

Git rebase is particularly useful when working on small or individual feature branches that will eventually be merged into a shared main branch. It’s also great for keeping your history clean and linear, which is particularly beneficial when working on open-source projects or when you need to maintain a project’s commit history for easy troubleshooting and understanding.

However, in team environments with multiple contributors, rebase should be used cautiously to avoid issues related to rewriting public history. It’s important to communicate with your team about when rebasing is appropriate and to ensure that everyone is aware of the potential for conflicts. In many cases, using git merge for integrating branches can be safer and simpler, especially when working on shared branches or when a non-linear history is acceptable.

Important Considerations
Copy link

  • Rewriting History

One of the critical aspects of git rebase is that it rewrites commit history, which means that the SHA-1 hashes of the rebased commits change. This can cause issues in collaborative environments, especially when you rebase a branch that has already been pushed to a shared remote repository. Rebasing changes the commit history, which may lead to conflicts with other developers who have based their work on the previous commit history. It can also cause problems when trying to push the rebased branch, as the remote repository will recognize that the local history no longer matches the remote.

  • Avoid Rebasing Public Branches

A common best practice is to avoid rebasing public branches that have already been shared with others. Since rebase alters the commit history, rebasing public branches that multiple developers rely on can result in divergent histories, leading to confusion and difficult-to-resolve merge conflicts. In general, git rebase is most appropriate for local branches or for preparing a feature branch for a final merge into a main branch. Public branches, especially ones that are already being worked on by others, should typically be merged instead of rebased.

  • Potential Conflicts

During a rebase, if there are changes in both the feature branch and the target branch that conflict, Git will stop and ask you to resolve the conflict manually. While resolving conflicts during a rebase is similar to doing so during a merge, rebasing requires you to resolve conflicts for each commit that has to be reapplied, potentially making it a more tedious process, especially with large feature branches. Once conflicts are resolved, you can continue the rebase with the git rebase --continue command.

Conclusion
Copy link

Merging two branches using rebasing, implemented with the git rebase command, is fundamentally different from the classic merge done with the git merge command.

  • git merge turns the commits of one branch into a single commit in another.

  • git rebase moves commits from one branch to the end of another while preserving the original order.

A similar rebasing effect can also be achieved when using the git pull command with the additional --rebase flag.

On one hand, the git rebase command allows you to achieve a cleaner and more understandable commit history in the main branch, which increases the maintainability of the repository.

On the other hand, git rebase reduces the level of detail in changes within the branch, simplifying the history and removing some of its records.

For this reason, rebasing is a feature intended for more experienced users who understand how Git works.

Most often, the git rebase command is used together with the git merge command, allowing you to achieve the most optimal repository and branch structure.