Search code examples
gitmergerebase

Git rebase instead of merge, the correct way to do it?


I would like to avoid recurrent branches intersections on my remote repository by using a rebase instead of a merge.

To give you a better understanding of what I would like to achieve, please consider the following situation:

$ git lg
* 2345678 hotfix (HEAD -> master)
* 1234567 foo (origin/master, origin/HEAD)

$ git push 
! [rejected]  master -> master (fetch first)

$ git fetch
$ git lg 
* 2345678 hotfix (HEAD -> master)
| * 3456789 other change (origin/master, origin/HEAD)
|/
* 1234567 foo

Usually, the standard way of solving this issue is a merge followed by a push.

$ git merge origin/master
$ git lg
* 4567890 Merge remote-tracking branch 'origin/master'
|\
* |  2345678 hotfix (HEAD -> master)
| * 3456789 other change (origin/master, origin/HEAD)
|/
* 1234567 foo
$ git push

I don't like this solution because I could easily avoid the branching in this particular case. So, let's revert the change with git reset --hard head~1 and try another solution instead:

$ git rebase origin/master
First, rewinding head to replay your work on top of it...
Applying: hotfix

$ git lg
* 2345678 hotfix (master)
| * 5678901 hotfix (HEAD)
| * 3456789 other change (origin/master, origin/HEAD)
|/
* 1234567 foo

Now comes the unpleasant part where I have to move my master back on its HEAD:

$ git branch -D master
$ git checkout -b master
$ git push
$ git branch --set-upstram-to=origin/master master
Branch master set up to track remote branch master from origin.
$ git lg 
* 5678901 hotfix (HEAD -> master, origin/master, origin/HEAD)
* 3456789 other change
* 1234567 foo

My question is how can I simplify my rebase and avoid the unpleasant part?


Solution

  • I think the easiest way is to change your pull workflow. There are a couple options here.

    First, you can use the --rebase flag to pull

    git pull --rebase
    

    Per the docs, git pull executes a fetch followed by a merge in its default configuration. Using the --rebase flag will replace the merge with a rebase :)

    Second, you can set a default to always do this with git pull

    git config --global pull.rebase true
    

    I would recommend the first approach, as setting a default of rebase makes me nervous. I created an alias git pr for git pull --rebase to make it easier. That way I can make the decision with each pull.