GIT rebase: don’t run that as magic command!

I have to be honest, rebasing a branch for me was like a magic trick. I have never spent time to really study the correct mechanism of rebasing and I have always simply followed what git asked me to do after having fixed the conflicts when found.

But that’s definitely not the right way to work with a version control system. You have always to be perfectly conscious of what you are doing, because vcs are powerful but at the same time dangerous tools.

So I decided to focus on studying about this topic, and googling I found out this question can’t push to branch after rebase well replied by Trev Norris.

Updating from a Remote Repository

Starting from this example

A-----C-----E-----G-----H-----I       master
 \
  B-----D-----F                      devel0

to stay up-to-date with remote master branch, the right workflow is

git fetch origin
git checkout master
git merge --ff origin/master

don’t use git pull as wisely suggested in the post Git: fetch and merge, don’t pull.

Why? Because:

  1. git pull works like a magic button which does many things automatically (fetch and merge) by itself and most of the time it properly works; but when it doesn’t, it’s often hard to figure out why;
  2. by both fetching and merging in one command, your working directory is updated without giving you a chance to examine the changes you’ve just brought into your repository.

(for more informations, I strongly recommend to take a look at the post previously linked, because definitions and reasoning about branches are very interesting and well written)

So, starting with the first command:

git fetch origin

it allows to get the changes from the remote repository into your local repository withouth touching your working tree at all. More in general, with that command you might get if there are remote changes without needing to switch from the devel0 branch. Furthermore, it’s a safety mechanism to make sure you don’t overwrite any un-stashed/committed changes.

If there are changes, after having analyzed the output message of git fetch origin (Git: fetch and merge, don’t pull well explaines how do that), you can checkout on the master branch:

git checkout master

and then you have to decide if you want to bring the changes from the remote branch into your working tree. So you might want to see what the differences are between the local branch and the remote one:

git diff master origin/master

If you want to get the changes from the master branch, you need just to merge the changes that you’ve just got from origin

git merge --ff origin/master

Rebasing your Local Repository

After having merged the remote changes, you can start the rebase of the devel0 branch

git checkout devel0
git rebase master
git push origin +devel0

where + before devel0 allows to force a push to only one branch. This is necessary for git push in this specific case because (quoting the push-manual page):

Usually, the command refuses to update a remote ref that is not an ancestor of the local ref used to overwrite it.

and this is what exactly happens after a rebase, because the ancestors of the local branch change. So

This flag disables these checks, and can cause the remote repository to lose commits; use it with care.

So don’t use it for normal push…NEVER!!!

At the end, the history will be a thing like the following

G-----H-----I                         master
              \
               B'----D'----F'         devel0

Just in case your starting history was (thanks to Trev Norris)

o-----o-----o-----o-----o-----o       master
 \
   o-----o-----o                      devel0
                 \
                  o-----o-----o       devel1

and you need to rebase both devel0 and devel1, after having rebased devel0 as previously described, you need to rebase devel1 following this workflow

git fetch origin
git checkout devel1
git rebase origin/devel0

and the final result will be

o-----o                                 master
       \
         o-----o-----o                  devel0
                      \
                        o-----o-----o   devel1

That’s all. But before thanks to

Happy hacking and GWH!!!

About Francesco Serafin

I am a PhD student at the Department of Civil, Environmental and Mechanical Engineering at the University of Trento. My two greatest loves: Computer Science and Water (take three with my Lenovo!:D). As a result, the aim of my life is to make both passions coexist. My gpg public key available at https://pgp.mit.edu

Leave a Reply

Your email address will not be published.

*