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
:
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):
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:
It is the same as issuing the two following commands:
Deleting a branch
When you are sure you won't need a branch anymore, you can delete it using git branch -d
:
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
:
If you don't specify the name of the branch to rename, it renames the branch currently in use:
Merging branches
Merging branches is particularly easy and efficient in Git. To merge a branch
named mybranch
into the current branch, simply use:
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):
The content in the top part, between<<<<<<< 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
<<<<<<<
and=======
represents the changes introduced inHEAD
(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.