Summary

The Git rebase command moves a branch to a new location at the head of another branch. Unlike the Git merge command, rebase involves rewriting your project history. It’s a great tool, but don’t rebase commits other developers have based work on.

The Gitrebasecommand combines two source code branches into one. The Gitmergecommand does that too. We explain whatrebasedoes, how it’s used, and when to usemergeinstead.

A diagram of a master branch and an unmerged branch called dev-branch

The Git Explosion

Frustrated with other version control systems and their slow updates and commits,Linus Torvalds, of Linux kernel fame, put aside a month in 2005 to write his own. He named it Git.

Sites likeGitHub,GitLab, andBitBuckethave symbiotically promoted and benefited from Git. Today Git is used globally, with a massive98 percent of 71 thousand respondentsin a 2022 survey using Git as the version control system.

Merging the dev-branch branch into the master branch

One of Git’s main design decisions was speed. In particular, working with branches had to be as fast as possible. Branches are a fundamental part of version control systems. A project repository will have a main or master branch. This is where the project’s code base sits. Development, such as new features, takes place in segregated side branches. This stops the work done in branches from messing up the master branch, and it allows simultaneous development to happen in different parts of the code base.

As the developments in the side branches are completed, the changes are transferred to the master branch by merging the development branch into the master branch. In other version controls systems working with branches was difficult and computationally expensive.Working with branchesin Git is very fast, and very lightweight. What was once a tedious and often avoided exercise in other systems, became trivial in Git.

The dev-branch branch merged with the master branch

The Gitrebasecommand is another way of transferring the changes from one branch into another branch. Themergeandrebasecommands have similar objectives, but they achieve their ends in different ways and yield slightly different results.

What Is Git merge?

So what isthe Gitmergecommandfor? Let’s say you’ve created a branch calleddev-branchto work on a new feature.

Youmake a few commits, and test your new feature. It all works well. Now you want to send your new feature to themasterbranch. You must be in themasterbranch to merge another to it.

The master branch with the dev-branch rebased onto it

We can ensure we’re in themasterbranch by explicitly checking it out before we merge.

We can now tell Git to merge thedev-branchinto the current branch, which is themasterbranch.

The master branch with the new-feature rebased onto it

Ourmergeis completed for us. If you checkout themasterbranch and compile it, it’ll have the newly developed feature in it. What Git has actually performed is a three-way merge. it compares the most recent commits in themasteranddev-branchbranches, and the commit in themasterbranch immediately before thedev-branchwas created. It then performs a commit on themasterbranch.

Merges are considered nondestructive because they don’t delete anything and they don’t change any of the Git history. Thedev-branchstill exists, and none of the previous commits are altered. A new commit is created that captures the results of the three-way merge.

Using the Git branch command to list the branches in the git repository

After the merge, our Git repository looks like a timeline with an alternative line branching off and then returning to the main timeline.

Thedev-branchbranch has been incorporated into themasterbranch.

If you have a lot of branches in one project, the history of the project can become confusing. This is often the case if a project has many contributors. Because the development effort splits into many different paths, the development history is non-linear. Untangling the commit history becomes even more difficult if branches have their own branches.

Note that if you have uncommitted changes in themasterbranch, you’ll need to do something with these changes before you can merge anything to it. You could create a new branch and commit the changes there, and then do the merge. You’d then need to merge your temporary branch back into the master branch.

The master branch with the dev-branch rebased onto it

That works, but Git has a command that achieves the same thing, without having to create new branches.Thestashcommandstores your uncommitted changes for you, and lets you call them back withstash pop.

git merge dev-branch

stash pop

The end result is a merged branch, with your unsaved changes restored.

What Is Git rebase?

The Gitrebasecommandachieves its aims in a completely different way. It takes all of the commits from the branch you’re going to rebase and replays them onto the end of the branch you’re rebasing onto.

Taking our previous example, before we performed any action our Git repository looks like this. We have a branch calleddev-branchand we want to move those changes to themasterbranch.

After therebase, it looks like a single, completely linear timeline of changes.

Thedev-branchhas been removed, and the commits in thedev-branchhave been added to the master branch. The end result is the same as if the commits in thedev-branchhad actually been directly committed to themasterbranch in the first place. The commits aren’t just tacked onto themasterbranch, they’re “replayed” and added fresh.

This is why therebasecommand is considered destructive. The rebased branch no longer exists as a separate branch, and the Git history of your project has been rewritten. You can’t determine at some later point which commits were originally made to thedev-branch.

However, it does leave you with a simplified, linear, history. Compared to a repository with dozens or even hundreds of branches and merges, reading the Git log or using a graphical git GUI to look at a graph of the repository, a rebased repository is a breeze to understand.

How to Rebase Onto Another Branch

Let’s try agit rebaseexample. We’ve got a project with a branch callednew-feature. We’drebasethat branch onto themasterbranch like this.

We swap back to themasterbranch

We merge the new-feature branch into the current branch, which in our case is themasterbranch.

Interestingly, we’ve still got two branches after the final merge.

The difference is, now the head of thenew-featurebranch and the head of themasterbranch are set to point to the same commit, and the Git history doesn’t show there used to be a separatenew-featurebranch, apart from the branch label.

Git Rebase vs. Merge: Which One Should You Use?

It’s not a case ofrebasevs.merge. They’re both powerful commands and you’ll probably use them both. That said, there are use cases whererebasedoesn’t really work that well. Unpicking mistakes caused by mistakes usingmergeare unpleasant, but unpicking errors caused byrebaseis hellish.

If you’re the only developer using a repository, there’s less chance of you doing something withrebasethat is disastrous. You could stillrebasein the wrong direction for example, andrebaseyour master branch onto yournew-featurebranch. To get yourmasterbranch back, you’d need torebaseagain, this time from yournew-featurebranch to yourmasterbranch. That would restore yourmasterbranch, albeit with an odd-looking history.

Don’t userebaseon shared branches where others are likely to work. Your changes to your repository are going to cause problems to a lot of people when you push your rebased code to your remote repository.

If your project has multiple contributors, the safe thing to do is only userebaseon your local repository, and not on public branches. Likewise, if pull requests form part of your code reviews, don’t userebase. Or at least, don’t userebaseafter creating the pull request. Other developers are likely to be looking at your commits, which means that those changes are on a public branch, even if they’re not on themasterbranch.

The danger is that you are going torebasecommits that have already been pushed to a remote repository, and other developers might have already based work on those commits. Your localrebasewill make those existing commits vanish. If you push those changes to the repository you’re not going to be popular.

Other contributors will have to go through a messymergeto get their work pushed back to the repository. If you then pull their changes back to your local repository, you’re then faced with unpicking a mess of duplicated changes.

To Rebase, or Not to Rebase?

Rebasemight be outlawed in your project. There may be local, cultural objections. Some projects or organizations considerrebaseas a form of heresy, and an act of desecration. Some people believe the Git history should be an inviolable, permanent record of what has happened. So,rebasemight be off the table.

But, used locally, on private branches,rebaseis a useful tool.

Push after you’ve rebased, and restrict it to branches where you’re the only developer. Or at least, where all development has stopped, and no one else has based any other work off your branch’s commits.

Do that and you’ll avoid any issues.

Related:How to Check and Update Your Git Version