Branching & Merging in Git
16 min read·Jan 1, 2025
In Git, a branch is a lightweight and isolated line of development that allows developers to concurrently work on new features, bug fixes, or experiments without affecting the main codebase.
The master branch
The master branch, nowadays called the main branch, is the default main line of development in a Git repository.
It is automatically created by Git when initializing a new repository.
It contains the production-ready code that represents the latest stable released version of the software.
When a set of features or bug fixes are deemed ready for release, the temporary branches they were developed on are then merged (or integrated) into the main branch, so that the new code becomes part of the main branch's history.
This history provides a clear and organized record of the project's evolution over time, and represents the chronological history of stable releases and major changes in the project.
Note: While master and main are the two most common names for this branch, Git doesn't enforce a specific name.
Listing existing branches
To get the list of existing branches, you can use the git branch command without arguments:
$ git branch
development
* master
Where the branch marked with an asterisk * represents the current branch in use, referred to as the checked out branch.
Creating a new branch
In essence, a branch is a type of "sandbox" environment to which you can make changes without affecting other branches.
A branch is always derived from another existing branch, and starts as a copy of this branch containing its entire commit history.
To create a new branch from the currently checked out branch, you can use the git branch command:
$ git branch <branch_name>
Where branch_name is the name of the new branch.
Example
For example, considering that the currently checked out branch is the main branch:
$ git branch
* main
This command will create a new branch named development, that contains the same files, directories, and commit history as the main branch:
$ git branch development
$ git branch
development
* main
Creating a new branch off a specific commit
By default, each branch is created from the currently checked out branch, starting at the commit referenced by the HEAD pointer.
To create a new branch starting at specific commit instead, you can use the git branch command with the following syntax:
$ git branch <branch_name> <commit_hash>
Where:
branch_nameis the name of the new branch.commit_hashis the hash of the commit to branch from.
Example
For example, considering the following commit history:
$ git log --oneline
e97698a (HEAD -> master) third commit
cd2bbfe second commit
9e01fd9 first commit
This command will create a new branch named development starting at commit 9e01fd9:
$ git branch development 9e01fd9
Which means that this branch will only contain the first commit in its history.
Branch naming conventions
When creating branches, it is common to use descriptive names that help identify their purpose without having to look at their commit history.
Moreover, standardized branch names can be linked to project management tools, such as Github Issues or Jira, making it easier to connect code changes to specific tasks and tickets.
The most common naming convention for branches is the following one:
<type>/[reference/]<title>
Where:
typeis a word describing the type of branch (e.g.feature).referenceis an optional identifier that references a ticket on a project management platform (e.g.issue-5132).titleis the name of the branch in kebab case (e.g.add-signup-form).
For example:
feature/add-signup-form
release/rc-3.2.1
bugfix/issue-5142/fix-database-encryption
Common branch types
Some of the most common types of branches include:
- Release branches: they are prefixed with the
releasekeyword and are used for preparing a new software release. They often regroup the commits of several branches. - Feature branches: they are prefixed with the
featurekeyword and are used for developing new software features or enhancements. - Bugfix branches: they are prefixed with the
bugfixkeyword and are used to address and fix specific bugs or issues in the software. - Hotfix branches: they are prefixed with the
hotfixkeyword and are used for emergency fixes to critical issues or bugs in the production code.
Switching between branches
As of Git version 2.23, to switch from the current branch to another branch, you can use the git switch command:
$ git switch <branch_name>
Where branch_name is the name of the branch you want to switch to.
Example
For example, the following command will switch from the master branch to the development branch:
$ git branch
development
* master
$ git switch development
Switched to branch 'development'
Creating and switching to a new branch
To simultaneously create a new branch and switch to it, you can use the git switch command combined with the -c flag (short for --create):
$ git switch -c <branch_name>
Merging branches
In Git, merging a branch essentially consists in integrating the commits of a branch into another branch.
To merge a branch, you must first check out the branch you want to integrate the changes into using the git switch command:
$ git switch <target_branch>
Then integrate the commits of the desired branch using the git merge command:
$ git merge <source_branch>
Upon success, Git will output the list of changed files and append the commits of the source branch to the history of the target branch.
Example
Let's consider the feature/web-server branch, that contains 4 more commits than the main branch:
$ git branch
* feature/web-server
main
$ git log --oneline
1f4f215 (HEAD -> feature/web-server) chore: add node_modules directory to gitignore file
f912db2 feat: create server loader module
ed13f9c feat: add express package
dc33745 feat: add app manifest
ae987a6 (main) feat: initial commit
To integrate the commits of the feature/web-server branch into the main branch, we must first switch to the main branch:
$ git switch main
Switched to branch 'main'
Then merge the commits of the feature/web-server branch, which will output the summary of files and changes:
$ git merge feature/web-server
Updating ae987a6..1f4f215
Fast-forward
.gitignore | 1 +
index.js | 4 +-
package-lock.json | 711 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
package.json | 14 +++
server.js | 13 +++
5 files changed, 742 insertions(+), 1 deletion(-)
create mode 100644 .gitignore
create mode 100644 package-lock.json
create mode 100644 package.json
create mode 100644 server.js
Resulting in the HEAD pointer of the main branch being moved from the commit ae987a6 to the commit 1f4f215:
$ git log --oneline
1f4f215 (HEAD -> main, feature/web-server) chore: add node_modules directory to gitignore file
f912db2 feat: create server loader module
ed13f9c feat: add express package
dc33745 feat: add app manifest
ae987a6 feat: initial commit
Resolving merge conflicts
When attempting to merge two branches, it may happen that Git is unable to automatically reconcile the branches' changes.
These conflicts often happen because both branches have made changes to the same part of a file, making it unclear which changes should be kept.
Step 1: Merging branches
In this context, when executing the git merge command, Git will pause the merge process and prompt you to resolve the conflicts manually in the listed files.
$ git merge feature/web-server
Auto-merging index.js
CONFLICT (content): Merge conflict in index.js
Automatic merge failed; fix conflicts and then commit the result.
Step 2: Reviewing conflicts
Within these files, Git will mark the conflicting changes with markers, such as <<<<<<<, =======, and >>>>>>>:
$ cat index.js
const server = require('./server.js');
<<<<<<< HEAD
server({ port: 8000 });
=======
server({ port: 3000 });
>>>>>>> feature/web-server
Where:
- The content between
<<<<<<<and=======represents your branch's changes. - The content between
=======and>>>>>>>represents the incoming changes from the other branch.
Step 3: Resolving conflicts
To resolve a conflict, you need to open the file pointed out by Git using your preferred text editor:
$ vim index.js
And decide which changes to keep by deleting the conflict markers and the unwanted lines, and saving the file:
const server = require('./server.js');
server({ port: 8000 });
Step 4: Committing changes
To indicate to Git that the conflicts have been resolved, stage and commit the file using the git add and git commit commands:
$ git add index.js
$ git commit -m "chore: resolve merge conflict on server port"
[main a359227] chore: resolve merge conflict on server port
Finally, if you were in the middle of a merge operation when conflicts occurred, you can continue the merge by running the git merge command with the --continue flag:
$ git merge --continue
Which will finalize the merge and create a merge commit.
Deleting branches
By nature, most branches are short-lived and meant to be deleted over time.
This could be because a feature has been completed and integrated into the main branch or because a feature has been discarded, among other things.
To delete a branch whose changes have been merged into another branch, you can use the git branch command with the -d flag (short for --delete):
$ git branch -d <branch_name>
Alternatively, to forcefully delete a branch with unmerged changes, you can use the -D flag, as Git will otherwise throw an error preventing you from deleting it:
$ git branch -D <branch_name>
Example
This command will delete the feature/web-server branch from the previous example, whose commits are already merged into the main branch:
$ git branch -d feature/web-server
Deleted branch feature/web-server (was e2e1613).
$ git branch
* main
Summary
Here's a summary of what you've learned in this lesson:
- The
masterbranch (ormain) is the default main line of development in a Git repository. - The
git branchcommand is used to list the existing branches. - The
git branch <branch_name>command is used to create a new branch. - The
git branch <branch_name> <commit_hash>command is used to create a new branch off a specific commit. - The
<type>/[reference/]<title>is the most common branch naming convention. - The
git switch <branch_name>command is used to check out an existing branch. - The
git merge <source_branch>command is used to merge a branch into the currently checked out branch. - The
git branch -d <branch_name>command is used to delete a branch with merged changes. - The
git branch -D <branch_name>command is used to delete a branch with unmerged changes.
Enjoying the courses?
I've made these courses completely free so anyone can learn from them. If they've helped you and you'd like to actively support the work behind BackendBrewery, you can leave a tip:
Support BackendBrewery