# Git: dealing with branches, merging and rebasing

Here's how to make, delete, list, and use branches. Plus solutions to some hairy
branching scenarios you might find yourself in.

## Branching models

There are two prevailing branching models:

1.  [git-flow](http://nvie.com/posts/a-successful-git-branching-model/)
2.  [github-flow](http://scottchacon.com/2011/08/31/github-flow.html)

The diagram for Git flow is so complex that I'm not even going to try to draw
any pseudo graphics for it. See the flowchart
[here](http://nvie.com/posts/a-successful-git-branching-model/).

GitHub flow goes like this:

```
Master  ●────●────●────●────●────●────●
                \      /
Feature  ┈┈┈┈┈┈┈●───●┈┈┈┈┈┈┈`</pre>
```

**GitHub Flow** is so _simple_ and _intuitive_ that it can be explained in a few
bullet points. Actually, in six:

> - Anything in the `master` branch is deployable
> - To work on something new, create a descriptively named branch off of
>   `master` (ie: `new-oauth2-scopes`)
> - Commit to that branch locally and regularly push your work to the same named
>   branch on the server
> - When you need feedback or help, or you think the branch is ready for
>   merging, open a pull request
> - After someone else has reviewed and signed off on the feature, you can merge
>   it into master
> - Once it is merged and pushed to `master`, you can and _should_ deploy
>   immediately

I'll quote Scott Chacon's
[article](http://scottchacon.com/2011/08/31/github-flow.html) once more:

> [In git flow] one of the bigger issues for me is that it’s more complicated
> than I think most developers and development teams actually require. It’s
> complicated enough that a big [helper script](https://github.com/nvie/gitflow)
> was developed to help enforce the flow.

I prefer **GitHub Flow exactly because of its simplicity**. This kind of
simplicity might not necessarily be a requirement for you, both models serve a
different purpose.

GitFlow is good for projects that have formal releases every few weeks or
months. Whereas, it's overly complex when there are no release cycles, like my
little blog here or GitHub projects where **there are new features and bug
fixes, but no version numbers**.

## Branch commands in Git

For a compact reference to creating, renaming, and deleting branches, see the
[Git branching command cheat sheet](/git-handy-branching-commands).

```
# List branches
$ git branch

# Make a branch
$ git branch my-new-branch

# Change into a branch
$ git checkout my-new-branch

# To create and checkout a branch in one command, use the `-b` flag
$ git checkout -b my-new-branch

# Delete local branch
$ git branch -d my-new-branch
```

### Examples

Here's a little bash script to generate a test repo to play with:

```
mkdir merge-test \
&& cd merge-test \
&& echo Banana > banana.txt \
&& echo Apple > apple.txt \
&& echo Kiwi > kiwi.txt \
&& git init \
&& git add -A \
&& git commit -m "Initial commit"
```

Put your beer down:

```
# See what branches there are, only master for now
$ git branch
* master

# Make a new branch
$ git branch new-fruit

# Then check again, the one with the asterisk
# is the active branch
$ git branch
* master
    new-fruit

# Make changes to the new-fruit branch,
# start by switching to it by checking it out
$ git checkout new-fruit

# Make some new fruits, add, and commit them.
# Just paste it to your terminal.
$ echo Orange > orange.txt && git add -A && git commit -m "Added Orange"
$ echo Plum > plum.txt && git add -A && git commit -m "Added Plum"
$ echo Pear > pear.txt && git add -A && git commit -m "Added Pear"
```

Now there's more "meat" in the tree: two branches, and the other one has three
more commits.

The tree can be printed out with the following command:

```
$ git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s"
* 622f05d        (new-fruit) Add pear
* cd74786        Add Plum
* c6a23e2        Add Orange
* 4ff629a        (HEAD, master) Initial commit
```

It's very straight, the tree is linear. More on that in the merging section of
the article.

Presented with pseudo graphics it looks like this:

```
            ┌───┌───┌─ The new fruits
            ▼   ▼   ▼
new-fruit   ●───●───●
            /
master    ●
          ▲
          └── Initial commit
```

## Merging

> In Git, there are two main ways to integrate changes from one branch into
> another: the **merge** and the **rebase**.

When talking about branching, one must also talk about **merging**. It is the
opposite of branching: you pull the branches back into the trunk. We'll talk
about rebase later on in the article.

```
$ git merge new-branch
```

That will merge the `new-branch` to the branch you are at. Git will decide the
merging algorithm for you, which come in two types:

1.  Fast forward merge
2.  and a 3-way merge (Ménage à trois hehe)

### Fast forward merge

Fast-forward merge can be used when there is a linear path to the new branch. In
other words, there have been no commits in `master` after `new-branch` diverged
from it.

If your git tree looks something like this:

```
                     ┌─ New feature
                     ▼
newbranch┈┈┈┈●───●───●
                /
master    ━━●━━●
                ▲
                └── Master
```

What the fast-forward merge does is simple: it copies the new feature to the
master:

```
                        ┌─ New feature and Master
                        ▼
                ●───●───●
                /
master ●───●───●
```

Nothing really changes, the linear structure remains, all commits are the same.

### 3-way merge

Take the below, very common, git tree:

```
                       ┌─ Your New feature branch
                       ▼
newbranch  ┈┈┈●───●───●
                /
master━━●━━●━━●
              ▲
              └── MASTER. Someone else merged
                  in their changes after you
                  branched out with your feature.
```

There's now two different histories that Git needs to smash together somehow. It
does this by using data from 3 different commits (hence the name). The commits
are: 1) master tip, 2) feature tip, 3) their ancestor.

```
                     ┌── 2
                     ▼
newbranch┈┈┈┈●───●───●
                /
master━━●━━●━━●
           ▲   ▲
       3 ──┘   └── 1
```

The three way merge also creates a merge commit.

### What merge algorithm to use then? And how?

Git does this for you. It uses fast-forward merging when it can. There is also
rebasing, which is closely related to merging. That's the next chapter in the
article.

### Merge examples

Let's pick up from the test tree where we left off in the first example. It
looked like this:

```
* 622f05d        (new-fruit) Add pear
* cd74786        Add Plum
* c6a23e2        Add Orange
* 4ff629a        (HEAD, master) Initial commit
```

Let's break the linearity by making a commit to the Master:

```
$ git checkout master
$ echo Pineapple > pineaple.txt
$ git add -A
$ git commit -m "Add Pineapple"
```

Now check it with the extended log command:

```
git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s"
* d41e17c        (HEAD, master) Add Pineapple
| * 622f05d      (new-fruit) Add pear
| * cd74786      Add Plum
| * c6a23e2      Add Orange
|/
* 4ff629a        Initial commit
```

The `new-fruit` branch is clearly visible now. Merge it into `master`:

```
# Switch to master if not active
$ git checkout master
$ git merge new-fruit
Merge made by the 'recursive' strategy.
    orange.txt | 1 +
    pear.txt   | 1 +
    plum.txt   | 1 +
    3 files changed, 3 insertions(+)
    create mode 100644 orange.txt
    create mode 100644 pear.txt
    create mode 100644 plum.txt
```

Git asks you to enter a commit message, since this is a three-way merge.

![Screenshot 2015-02-25 09.44.59](/images/Screenshot-2015-02-25-09.44.59.png)

Now the log shows the following:

```
$ git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s"
*   ef27c6c      (HEAD, master) Merge branch 'new-fruit'
|\
| * 622f05d      (new-fruit) Add pear
| * cd74786      Add Plum
| * c6a23e2      Add Orange
* | d41e17c      Add Pineapple
|/
* 4ff629a        Initial commit
```

`new-fruit` has merged into the trunk. Now there's a "Merge branch 'new-fruit'"
commit and the history is not linear. Rebasing can help in that.

## Rebase

Rebasing is similar to merging because it also combines branches, but it is a
completely different command. Rebase rewrites history and can reduce merge
conflicts. What does this mean? Let's look at how rebasing works.

An example tree:

```
                        ┌─ FEATURE
                        ▼
newbranch          ●───●
                  /
master───●───●───●─────●───●
                           ▲
                           └── MASTER
```

After a rebase, the `feature` branch kind of 'migrates' to the tip of the tree:

```
the "old" FEATURE ─┐         ┌─ FEATURE
                   ▼         ▼
newbranch          ●───●     ●───●
                  /         /
master───●───●───●─────●───●
                           ▲
                           └── MASTER
```

Essentially, rebase moves a commit from one branch to another. But **those
commits are not the same commits, they contain the same stuff, but they're new
commits**, they have different commit ID etc. So, rebase rewrites history.

Without rebase you wouldn't be able to retain linear history, rebasing tidies up
the repo.

Rebasing won't replace merging. They are usually used together: rebase first,
then merge.

### Rebase examples

This is where we left off in our example tree:

```
$ git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s"
*   ef27c6c      (HEAD, master) Merge branch 'new-fruit'
|\
| * 622f05d      (new-fruit) Add pear
| * cd74786      Add Plum
| * c6a23e2      Add Orange
* | d41e17c      Add Pineapple
|/
* 4ff629a        Initial commit
```

First let's rollback that merge commit, so we can test the rebasing better:

```
# Roll back 1 commit
$ git reset --hard HEAD~1
HEAD is now at d41e17c Add Pineapple
```

Now we want to:

1.  Rebase the `master` to `new-fruit` and then
2.  merge `new-fruit` to `master`.

```
$ git checkout new-fruit
$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: Add Orange
Applying: Add Plum
Applying: Add pear

# Then merge
$ git checkout master
$ git merge new-fruit
```

Note that it didn't ask us to write a commit message, because there's no need to
do that, because Git only did a fast forward merge. Now the log shows a linear
history:

```
$ git log --graph --full-history --all --pretty=format:"%h%x09%d%x20%s"
* f5777c2        (HEAD, new-fruit, master) Add pear
* 31a525b        Add Plum
* 72c2e92        Add Orange
* d41e17c        Add Pineapple
* 4ff629a        Initial commit
```

There's one commit less and it's much tidier.

For instance, the Plum commit before the rebase was `* cd74786 Add Plum`, and
afterward it was `* 31a525b Add Plum`. The commit IDs differ because they're
completely different commits now and the old commits are destroyed. History
rewriting in action.

### When to rebase

Atlassian has
[great article](https://www.atlassian.com/git/articles/git-team-workflows-merge-or-rebase/)
about the little nuance differences of merging and rebasing.
[Git's docs](http://git-scm.com/book/en/v2/Git-Branching-Rebasing) are amazing
on this subject also.

## Common branching scenarios and problems

### The "forgot to make a feature branch" problem

You've started to work on a new feature, and forgot to make a new branch for it.
This is what you have:

```
master ●───●───●───●───●───●
                ^
                └── start a new feature
```

And this is what you want:

```
newbranch   ┈┈┈┈┈●───●───●
                /
master ●───●───●
```

This is very easy to solve with some branch juggling. Start by making a new
branch:

```
$ git branch newbranch
```

Now, all your new stuff is safe in the new branch, and you can freely roll back
on the master:

```
$ git reset --hard HEAD~3 # This goes back three commits
```

Or rollback to a commit id

```
$ git reset --hard <commit-id>
# Commit IDs look like this 5c00039c86ca321e9ac41557e6515da20cfeee44
# You can see your commit ID by issuing: git log
```

There you have it, `newbranch` has the new stuff and `master` has the old. Watch
for not going back too far.

Then check out the `newbranch` to continue work on it:

```
$ git checkout newbranch
```

### The "tip of your current branch is behind its remote counterpart" problem

You branch off from the trunk and hack on your feature, at this time someone
else finishes their feature and pushes it to the master. When you try to push
you get an error:

```
$ git push origin master
error: failed to push some refs to '/path/to/repo.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Merge the remote changes (e.g. 'git pull')
hint: before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
```

Now, you need to pull the changes from the remote master to your branch, using
the `--rebase` flag:

```
$ git pull --rebase origin master
```

It grabs the new commits from the Master and puts them at the tip of your
feature branch. Now you can push to it.

## Conclusions

Branching and rebasing are totally confusing at first, but they're an essential
part of Git. Learn to love them :) Please drop a comment if you got something to
add.
