A compilation of documentation   { en , fr }

Basic use of branches in Git

Tag:
Created on:
Author:
Xavier Béguin

Displaying the list of the existing branches

Simply use git branch with no option to get a list of the existing branches in your Git project (it is the same as using git branch --list).

$ git branch
  devel
* master

Showing the current branch

In the output of the git branch command above, the branch marked with an asterisk (and highlighted in green on a terminal) is the branch you are currently on:

  devel
* master

To only show the branch currently in use, use the --show-current option:

$ git branch --show-current
master

In Git, the current branch is made special by two things:

  • the special marker HEAD points to it (it mostly behaves like a branch name);
  • the files in the working directory are in the same state as in the last commit of this branch.

Creating a branch

Creating a new branch is as easy as calling git branch with the name of your new branch. This example will create a branch named mybranch:

git branch mybranch

Creating a new branch does not change the current branch. It only declares a new pointer in the Git directory of your project that points to the last commit of the current branch.

Switching to another branch

To switch the current branch to another branch, use the git checkout command with the name of the target branch (mybranch in this example):

git checkout mybranch

Switching to another branch will modify the working directory of your Git project and update its files to reflect the states of the files in the last commit of the branch you are checking out.

The other effect of changing the current branch, beside changing the files in the working directory, is that the HEAD special pointer will point to the checked out branch (as it always points to the commit whose files are shown in the working directory).

As Git changes the files in your working directory, if you have made uncommitted changes to them or to your staging area, it would not know what to do with these changes. By default, Git will then refuse to check out the branch. You must either commit your changes or stash them before switching the branch (you could use the git stash command for that).

Creating a new branch and switch to it

To create a new branch and immediately switch to it, use the git checkout -b command:

git checkout -b mynewbranch

It is the same as issuing the two following commands:

git branch mynewbranch
git checkout mynewbranch

Deleting a branch

When you are sure you won't need a branch anymore, you can delete it using git branch -d:

git branch -d mybranch

Deleting a branch that wasn't fully merged into another one would make you lose the changes introduced by commits of that branch. Git will thus by default refuse to delete a branch that is not fully merged (unless you use the option -D, at your own risk).

Renaming a branch

If you need to rename a branch, use git branch -m:

git branch -m oldbranchname newbranchname

If you don't specify the name of the branch to rename, it renames the branch currently in use:

git branch -m newbranchname

Merging branches

Merging branches is particularly easy and efficient in Git. To merge a branch named mybranch into the current branch, simply use:

git merge mybranch

Depending on a few subtleties (see below), the merge will use either the fast-forward or the three-way merge strategy. Only the latter will produce a commit called a merge commit.

Additionally, sometimes conflicts between the changes introduced in the two branches cannot be automatically resolved. This is called a merge conflict and it must be dealt with manually (see below as well).

Fast-forward merge

If the last commit of the current branch is an direct ancestor of the last commit of the branch you want to merge, Git will use the fast-forward strategy to merge the branches, which consists in simply moving the branch pointer forward.

To illustrate this merge type visually, suppose you have a master branch with three commits A, B and C and a mybranch branch with two more commits D and E: the fast-forward strategy can only be applied if the last commit on master, C, is also part of mybranch, like in this diagram:

A---B---C master
         \
          D---E mybranch

After the merge, the configuration would look like this:

A---B---C---D---E master
                ^
                |
             mybranch

In this illustration, after the merge, master and mybranch both point to the same commit E.

Below is an example of output of a fast-forward merge (pulled from the chapter 3.2 of the Pro Git Book):

$ git checkout master
$ git merge hotfix
Updating f42c576..3a0874c
Fast-forward
 index.html | 2 ++
 1 file changed, 2 insertions(+)

Three-way merge

If the commit on the branch you are on is not a direct ancestor of the branch you are merging in (in other words, the commit where the histories of the two branches meet is not the last commit of the current branch), Git will have to use the three-way merge strategy: it will create a new commit called a merge commit that is special in that it has more than one parent.

This strategy is used when a fast-forward merge is not possible, like in the example illustrated below:

A---B---C master
     \
      D---E mybranch

Following the three-way merge strategy, a new commit F is created to resolve the merge of mybranch into master. The resulting configuration of commits would look like this (F is a merge commit):

A---B---C---F master
     \     /
      D---E mybranch

This is an example ouput of a three-way merge (pulled from the chapter 3.2 of the Pro Git Book):

$ git checkout master
Switched to branch 'master'
$ git merge iss53
Merge made by the 'recursive' strategy.
index.html |    1 +
1 file changed, 1 insertion(+)

Git will by default open your editor for you to edit the default log message for merge commits (which would simply says Merge branch 'iss53' in the example above).

Git offers the possibility to force the creation of a merge commit in all cases (even when a fast-forward merge is possible) using the option --no-ff with git merge.

Converserly, the option --ff-only can be used to refuse to merge using the three-way merge strategy: if the merge cannot be resolved as a fast-forward, git merge will refuse to merge and will exit with an error.

By default git merge uses the option --ff that resolves the merge as a fast-forward when possible and only create a merge commit if it is not.

Theses options are presented in the git-merge manual page.

Merge conflicts

Finally, if the branches to be merged changed the same part of a file in a different way, Git won't be able to decide which version should be kept: this is a merge conflict that must be resolved manually.

In this case, Git will pause the merge and warn you with a message stating that one or more conflicts emerged and that you must fix them. The command git status will then also show you the conflicting file(s) (designated as unmerged paths).

This is an example of what Git would show you when the merge results in a conflict (example also pulled from the chapter 3.2 of the Pro Git Book):

$ git merge iss53
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

And here is an example output of git status showing the conflicting file (index.html here):

$ git status
On branch master
All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

    modified:   index.html

In such a case, you would have to:

  • edit the conflicting file(s) to choose which version of the conflicting part(s) of the file you want to keep. Git will show both versions in each files using markers like in this content example (from the Git Pro Book):
    <<<<<<< HEAD:index.html
    <div id="footer">contact : email.support@github.com</div>
    =======
    <div id="footer">
     please contact us at support@github.com
    </div>
    >>>>>>> iss53:index.html
    
    The content in the top part, between <<<<<<< and ======= represents the changes introduced in HEAD (which means the current branch), and the bottom part, between ======= and >>>>>>> is the content introduced in the branch you are merging (iss53 in this example). You must suppress the markers and only keep the version of the content you want to preserve (which you can obviously edit based on one of the branch versions);
  • once the conflicted file(s) are modified and saved, use git add to mark the files as resolved;
  • commit the merge. Git will propose a default commit message showing the merged branch and the conflicting file(s). You can edit it to explain the choices you've made. Here is the default message corresponding to the example given above:
    Merge branch 'iss53'
    
    Conflicts:
      index.html
    

Once this merge commit is recorded, the merge is finished.