git merge or rebase

Asked

Viewed 5,931 times

12

When I program using git, I always use merge from my branch in master to add new code, but some graphic tools like smartgit rebase instead of merge.

I must use the command rebase or merge to add my changes to my master branch?

2 answers

20


Let’s consider the scenario below to better understand what happens and which option to use:

--- A --- B --- C --- D --- remotes/origin/master
           \
            --- E --- F --- master

Let’s say you based your work on the B commit, and created the E and F commits, and meanwhile added the C and D commits to the remote branch. The merge can work in two ways: fast forward and merge commit. The fast forward only works if you didn’t commit any, which is not the case. In cases where fast forward is possible, there is no difference between using it and rebasing.

The merge commit will look like this:

--- A --- B --- C --- D --- remotes/origin/master
           \           \
            --- E --- F --- M --- master

That is, it creates the M commit, which has two parents: the last commits on your branch and the branch you’re merging.

It already demotes him like this:

--- A --- B --- C --- D --- remotes/origin/master
                       \
                        --- E' --- F' --- master

The main advantage of rebase is that its story remains linear: every commit has a single parent. But note that commits E and F no longer exist on your branch: what they do exist are commits E' and F', which are equivalent to the original E and F, but different. The main drawback is the following: let’s say you’ve published your branch in the "meurepo repository":

--- A --- B --- C --- D --- remotes/origin/master
           \
            --- E --- F --- master, remotes/meurepo/master

And someone else made Fork from that repository of yours and did something to it:

--- A --- B --- C --- D --- remotes/origin/master
           \
            --- E --- F --- master, remotes/meurepo/master
                       \
                        --- G --- remotes/outrorepo/master

Now you’ve rebased, and added a commit:

--- A --- B --- C --- D --- remotes/origin/master
           \           \
            \           --- E' --- F' --- H -- master
             \
              - E --- F --- G --- remotes/outrorepo/master

Now the other person has serious problems. Commits E and F and commits E' and F' are different, which can bring serious problems to the other person if they try to merge. Also, the other person can’t do a rebase with the same ease as you (it is possible, but requires that they know exactly the point where you did the rebase -- trivial above, but not so much in practice).

Let’s see what the merge option looks like, and I’ll include the other person’s branch:

--- A --- B --- C --- D --- remotes/origin/master
           \               \
            --- E --- F --- M -- H -- master, remotes/meurepo/master
                       \
                        --- G --- remotes/outrorepo/master

Note that an M commit has now been created. This commit has two parents: D and F. The main one downside this type of operation is precisely this lack of linearity. It is harder to pinpoint the exact moment when a problem has been entered into the code (in the example above it seems easy, but think about how it looks if everyone regularly merges like this).

There are two advantages. The first is that merging it is simpler: because the story has been preserved, git already knows that E and F commits are common between remotes/meurepo/master and remotes/outrorepo/master, and can be ignored when checking conflicts.

The other advantage is that it’s easier to understand what the people who were working on the code were thinking. Let’s say someone else created a bug in H, caused by the interaction of C with E. In the case of merge, they know that C and E were developed independently, and so the interaction is unexpected. In the case of rebase, she will find that you already knew the interaction when creating E', because the story is linear, and will be in doubt whether it was intentional or not.

The rule that seems to me to be the most recommended one is the following: while you don’t publish your branch, you can rebase. Once published, merge. However, rebases are widely used in the Linux community, which is the creator of git, which serves as a counterpoint.

  • Good point in the last sentence: rebase is not a possible thing to do with patches once published.

  • Very well explained. The rebases are amazing to make the "drawing" beautiful, but to work together are inadvisable, as stated by @epx above. Now if only you have the "Feature branch" in your repository, or if you’re sure that only you have touched it, then it’s very worth doing the rebase. With rebase, too, it is easy to remove some functionality if necessary.

7

Depends in part on your taste.

The "merge" brings together two separate development lines. It’s easier to do and any developer can at any time merge with the "official repository".

But many project maintainers who use Git don’t like merge commits, because they’re kind of opaque. Each merge commit has two different "parents". The project’s history ceases to be linear.

"Rebase" allows you to rewrite the "history" of the repository. Among other things, this allows you to reform your commits before they are sent to the "official repository".

This allows you to maintain the illusion that the development history is perfectly linear and serial, a commit having only one parent. Makes it much easier, for example, to do a regression test to find which commit introduced a bug.

For reference, articles I wrote about: Git merge: one legitimate use and a Goof and The Many faces of git rebase

Browser other questions tagged

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