Branch is a core concept in Git and many other version control systems. Generally speaking, a branch is a line of development which is parallel and independent of all other lines but which still shares the same history with all other branches if you look far enough in time. Because the branches are independent the changes applied to one branch does not automatically propagate to other branches and are not visible there. This way the development can be done in parallel by many contributors without disturbing each other.
Mainline
Git by default (after creating a repository) comes with a single branch named master. This branch represent the main development line (often named mainline) of the repository and is a branch from which new branches can be created of. It is also the destination branch where other branches can be merged to.
Of course, new branches doesn’t have to be created directly of this branch and merged directly into it but may also be created from other custom branches and merged into them.
Feature branches
A typical reason to create a branch is to have a “private space” to develop a new feature without disturbing other people’s work and being disturbed by them. It also keeps the mainline free from questionable and incomplete code. Only after the feature is finished and tested on the feature branch, it is merged as a whole into the mainline. Usually, after merging the feature branch can be safely deleted.
Bug-fix branches
Another reason to create a branch is to develop a bug-fix. Because the same bug is often present in many different branches (mainline and few releases), it is generally easier and faster to create a new branch with the bug-fix and merge it into all branches where the bug is present. It is completely fine if such branch contains a single commit only.
Experimental branches
A branch can be also created to experiment with tentative idea without affecting other people’s work. If the experiment turns out very well, the experimental branch may be merged back. If it fails, the experimental branch can be deleted without any merging.
Release branches
Branches are also used to take a snapshot of the mainline at some point in time and prepare it for release. Usually, only bug-fixes and small improvements are added to a release branch in order to stabilize it and get ready for final testing and build.
Creating branches
Creating a branch in Git is very easy:
$ git branch feature1-branch
The created branch feature1-branch is a child of the current branch and has exactly the same history up to the moment they were branched. The command above merely creates a branch so if you want to work on the new branch, you have to switch to it using command:
$ git checkout feature1-branch Switched to branch 'feature1-branch'
After this you can safely commit changes to the new branch similarly as you would do with the mainline.
There is also a shorthand command which creates a branch and immediately switches to it:
$ git checkout -b feature1-branch Switched to a new branch 'feature1-branch'
As you should know Git has a notion of local and remote repositories. The branch we have just created is a local one and is present only in a local repository. Usually, you would want to push this new branch to a remote repository so that other team members can access and work on it:
$ git push -u origin feature1-branch Total 0 (delta 0), reused 0 (delta 0) To file:///home/robert/tmp/git2/ * [new branch] feature1-branch -> feature1-branch Branch feature1-branch set up to track remote branch feature1-branch from origin.
Option -u ensures that the local branch tracks the new remote branch. This way Git is able to find the right local branch when pulling the changes from a remote repository using argument-less git pull command.
Listing branches
With git branch command you can also see all local branches:
$ git branch * feature1-branch master
all remote branches:
$ git branch -r origin/HEAD -> origin/master origin/feature1-branch origin/master
or just all (local and remote) branches:
$ git branch -a * feature1-branch master remotes/origin/HEAD -> origin/master remotes/origin/feature1-branch remotes/origin/master
The branch annotated with an asterisk is the current branch. Additionally, Git provides an option to list branches which are already merged into the current branch (either directly or indirectly):
$ git branch --merged feature1-branch * master test
There is also an opposite option –no-merged. These two options are very useful in determining which branches can be safely deleted from the repository.
Switching between branches
As shown before switching between branches is done using git checkout command:
$ git checkout feature1-branch Switched to branch 'feature1-branch'
All untracked files and local uncommitted changes in the working tree are left untouched so they can be later committed to the new branch. If the target branch is not found in the local repository but there exists a tracking branch in exactly one remote repository, the command creates a local branch pointing to the remote one and switches to it.
Deleting branches
If a branch was fully merged and is no longer needed, it can be deleted with command:
$ git branch -d bugfix1-branch Deleted branch bugfix1-branch (was b12dd4e).
If it was not merged and we don’t plan to do so for some reason, we can remove the branch forcefully:
$ git branch -D experimental1-branch Deleted branch experimental1-branch (was b12dd4e).
These commands operate on the local repository only so after removing a local branch, it is usually a good idea to remove the same branch from the remote repository:
$ git push origin :experimental1-branch To file:///home/robert/tmp/git2/ - [deleted] experimental1-branch
While this looks almost like pushing a new branch to a repository, there is a slight difference – a colon before branch name (actually empty branch name before the colon) which informs Git that the branch should be removed rather than created. If the command is too obscure to you, an alternative may be used:
$ git push origin --delete experimental1-branch To file:///home/robert/tmp/git2/ - [deleted] experimental1-branch
Synchronizing with remote
Even if a local branch has a tracking remote branch in the remote repository, the changes committed to the local branch won’t automatically appear in the remote one. Changes made to the current local branch can be pushed to the remote repository (possibly with changes to other branches depending on Git version and configuration) using command:
$ git push
Additionally, to fetch changes made by other developers in a remote tracking branch and apply them to the current local one, the pull command can be used:
$ git pull
When working in many people on a project, you may end up in a situation that somebody removed a branch from a remote repository but you still see it in the output of git branch -a command even after running git pull many times. It is because git pull does not automatically prune no-longer-existing branches and it has to be done manually:
$ git remote prune origin Pruning origin URL: file:///home/robert/tmp/git2/ * [pruned] origin/feature7-branch
Merging
When a new child branch is created based on a parent branch, they have exactly the same history. But once you start applying changes to one of them, their histories start to diverge. At some point you may decide that you want to share some of the changes from one of the branches (usually child branch) with another one (usually parent branch). This concept is commonly called merging in version control systems. After merging, the changes from the source branch will become available and visible in the destination branch.
To merge a branch into another one, you have to switch to the destination branch and then run git merge command with the name of the source branch to merge in:
$ git merge feature11-branch Updating b12dd4e..0b7f55a Fast-forward ABC.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 ABC.txt
Of course, after this the source branch may be deleted and the changes to the destination branch should be pushed to a remote repository.
In case Git complains about conflicts during merge operation, you can refer to the article explaining how to resolve merge conflicts.
Conclusion
Branching and merging is one of the most important concepts in version control systems that every developer should know. In this article I have concentrated on the basics which should be enough in most cases. For details you can always consult git-branch, git-checkout and git-merge manual pages.