Guide language:Git rebase leads to a linear history with no branching. Further problems can be introduced if conflicts occur during the Rebase process. The author recommends git Merge.

After working with Git for a few years, I’ve found that using more and more advanced Git commands has become part of my daily workflow. As soon as I discovered Git Rebase, I incorporated it into my daily workflow. Anyone familiar with Rebase knows how powerful it is, and it’s always tempting to use it. However, I soon discovered some of the less obvious challenges that came with starting to use Rebase. Before I get to the challenges, I’ll quickly talk about the difference between Merge and Rebase.

Let’s first consider the basic case of merging the feature branch into the Master branch. With merge, we create a new commitgRepresents the merger of two branches. The commit diagram clearly shows what’s going on, and we can see the familiar “train track” outline in the larger Git-repos.

Example of merging
Copy the code

Similarly, we can select Rebase before merge. The referral is removed, the feature branch is reset to the master branch, and the commit on the feature branch is reapplied to the master. The difference is that these reapplied commits are usually original copies with a different SHA-1 key than the original commits.

Example of rebasing
Copy the code

We now commit the base of the feature frombInto thecThat’s what rebase means. Merging a feature into the master is a fast-forward merge, because all commits on the feature are direct descendants of the master.

Example of fast-forward merging
Copy the code

In contrast to the merge method, rebase results in a linear branching history. The reason I used to prefer rebase branches before merging was for readability, and I think the same is true for other developers.

However, this approach presents some less obvious challenges.

Consider the case where a dependency has been removed on the master but is still used on the feature. When the feature branch rebase onto the master, the first reapplied reference breaks your build, but as long as there are no merge conflicts, the Rebase will not be broken. Errors from the first commit are retained in all subsequent commits, resulting in a chain of false commits.

This error is only discovered after rebase is complete, and usually a bug fix submission is added at the topg.

Example of failed rebasing
Copy the code

If you have a conflict during the rebase process, Git will pause the commit of the conflict, allowing you to resolve the conflict before you start. Resolving conflicts in the middle of a series of commits is often confusing, difficult to correct, and can lead to additional errors.

The import error occurred during the Rebase process. That way, when you rewrite history, new errors are introduced that may cover up the real mistakes made when it was written in the first place. In particular, it becomes more difficult to use Git Bisect, arguably the most powerful debugging tool in the Git toolkit. For example, consider the following feature branch, where we assume that an error is introduced at the end of the branch.

A branch with bugs introduced towards the end
Copy the code

To find submissions that introduce errors, you might search dozens or even hundreds of submissions. This process can be performed automatically by writing scripts where test errors exist and run with Git bisect using the command Git bisect run

.

Bisect identifies submissions that introduce bugs by bisecting the entire history. In the case shown above, it succeeds in finding the first incorrect commit, because all the problematic commits contain the real errors we are looking for.

Example of successfull Git bisect
Copy the code

On the other hand, if we introduce additional error commits in the rebase process (as shown in the figure below)dande), Bisect will be in trouble. In this case, we want Git to recognizefCommit, but it will incorrectly identifydBecause it contains other errors that break the test.

Example of a failed Git bisect
Copy the code

The problem is bigger than it seems.

Why do we use Git?

Because it’s the most important tool we have for tracking down the source of errors in our code. Git is our safety net. Linear history can be achieved with Rebase, but we give it less priority.

To recap, I had to track hundreds of submissions using the Bisect system. The incorrect commit was in the middle of an uncompiled commit chain because of an incorrect rebase. This unnecessary and avoidable error today caused me to spend the day tracking submissions.

So, how can we avoid errant commit chains during rebase? One approach is to test the code after rebase to find the error, then go back to where we introduced the error and fix it. Another approach is to pause each step in the Rebase process and test and fix it before continuing.

It’s a cumbersome, error-prone process. The only result of doing this is to get a linear history. Is there a simpler, better way?

Git merge It is a simple, one-step process where all conflicts can be resolved in a single commit. The submission of the merge clearly shows the points of interaction between our branches, and our history recounts what actually happened and when.

In summary, merge is recommended over Rebase. Keeping the truth of our history is not to be underestimated. As for why people use Rebase, it’s probably vanity, Koko.

  • Translator: KenChoi
  • Why you should stop using Git rebase
  • Zhihu column: Aurora Daily