How does the git rebase command work?

Asked

Viewed 39,504 times

37

What happens when you rebase in the following situation:

  1. Branch master with 3 commits (A, B and C).
  2. After committing C, I created a new branch with the name design.
  3. I committed (D) to the design branch and went back to the master branch.
  4. I committed (E) to the master branch.

Currently my commit history is:

  • master: A, B, C, E
  • design: A, B, C, D

After rebasing on the master branch, the history will be as follows?

  • master: A, B, C, D, E
  • design: A, B, C, D

If the answer is yes, what’s the point of rewriting the history when one of Git’s advantages is to be able to see the history as it is? If I can manipulate the history, then I might not see what really happened.

  • 2

    rebase is usually useful when only you touch a particular project, but when you don’t want to waste time merging, it overwrites the history with updates and ignores conflicts, keeping its update as the latest and also despises changes in the middle of the project made by other people.

3 answers

29

By answering your questions.

1 - After rebasing on the master branch, the history will be as follows?

Yes

2 - If the answer is yes, what is the purpose of redoing the history when one of the advantages of GIT is being able to view the history just like it is?

The problem of rebase is that it changes the history as well as other git commands (such as those that carry the attribute --hard). This is why it is recommended only in very specific cases. Git does not have the premise of protecting the history of changes at any cost, but of preserving this by default.

See below what happened in each commitwho made.

Remembering that HEAD is where your repository is currently pointing to (could be a branch, tag or commit specific).

Understanding the step-by-step scenario

Next, I will detail what occurred in each step you described until the rebase.

Come on:

Branch master with 3 commits (A, B and C).

A<---B<---C
          |
          |
       |Master|
          |
         HEAD

Commando:

git checkout master

After committing C, I created a new branch with the name design.

        HEAD
          |
       |design|
          |
          |
A<---B<---C
          |
          |
       |Master|

Commando:

git commit -m "Commit C"
git checkout -b design      # cria a branch design a partir da branch atual (master)

I committed (D) to branch design

                  HEAD
                    |
                |design|
                    |
                    |
                .---D
               /
A<---B<---C<--´
          |
          |
       |Master|

Commando:

git checkout design
git commit -m "Commit D"

and went back to the master branch.

                |design|
                    |
                    |
                .---D
               /
A<---B<---C<--´
          |
          |
       |Master|
          |
         HEAD

Commando:

git checkout master

I committed (E) to the master branch.

                |design|
                    |
                    |
                .---D
               /
A<---B<---C<--´-----E
                    |
                    |
                |Master|
                    |
                   HEAD

Commando:

git commit -m "Commit E"

And making the rebase:

                |design|
                    |
                    |
                .---D<----E'
               /          |
A<---B<---C<--´           |
                       |Master|

Commando:

git checkout design
git rebase master

As you can see, with the rebase from master on branch design, the more commits (E) of master go to the top of the branch design.

So, as you can see at the end, the commits turned out like you said:

  • master: A, B, C, D, E
  • design: A, B, C, D
  • 4

    One of the best explanations I’ve read... To complete would put the commands relating to commits and rebase in your example.

  • 1

    @Diegoborges, done :)

  • 1

    @Dherik, I think the last drawing is wrong. "COMMIT E" goes to the BASE branch "DESIGN". That’s why the name "rebase". That is, the COMMIT E is behind the "COMMIT D". Being the "COMMIT D" the "HEAD."

  • 1

    @Gbisconcini is right, the branches also end up pointing to the same commit (I think that’s why nobody noticed the problem so far). I’ll fix it later. (feel free to edit it if you want)

26


The main benefit of rebase is that begins a much more "clean approach".

First, it eliminates unnecessary intercalation, a commitment required by git merge.

Second, rebasing also results in a perfectly linear design history where you can follow the start of the entire path of the project without any problems. This makes it easier to navigate your project with commands like git log, git bisect and gitk.

But there are two compromise solutions to this story:

  • Security and traceability: if you don’t follow the golden rule of rebasing, rewriting the project’s history can be potentially catastrophic to your collaborative workflow. And, less importantly, rebasing loses the context provided by a merge commit, if you cannot see when the upstream changes have been incorporated into the resource.

The best way to understand the whole process is for example to read the following article:

Merging vs Rebasing

I also leave here images that summarize a good example of application:

Initial Status of the Repository

inserir a descrição da imagem aqui

Dev-B: Synchronization of Origin

inserir a descrição da imagem aqui

Dev-B: rebase

inserir a descrição da imagem aqui

Dev-B: final rebase

inserir a descrição da imagem aqui

Dev-B: Final Sync for Source

inserir a descrição da imagem aqui

14

That’s exactly what happens. The main advantage of rebase in relation to the merge is that you will have a much cleaner history (and how it really is) than a project with merges, since it will first apply all the commits of the branch that is "rebaseating", and then apply the commits of the branch that is being "rebeseado". Entertaining, rebase may result in some code losses that will not occur on merge, so it is indicated that beginners do not use the rebase, but rather the merge.

In addition, the golden rule of rebasing defines when to make a rebase. The rebase is advised only for private branches, ie it should be avoided in public branches, like the master, for example. This prevents you from messing up public branches by reorganizing your commits.

In summary, the rebase serves precisely to maintain a cleaner and more linear history, avoiding "unnecessary" commits occasioned by an eventual merge conflict. Remember that some tools only work with the rebase, as is the case with Gerrit, which creates a dependency line of the commits sent to with the main branch (usually the master).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.