Why This Matters
Real software development rarely happens in a straight line. You need to fix a bug while also building a new feature, or three teammates need to work on different parts of the codebase at the same time. Branches solve this by letting you create independent lines of development that diverge from a shared history and can later be combined.
A merge brings two branches back together. When changes do not overlap, Git handles this automatically. When two branches edit the same lines, you get a merge conflict -- Git stops and asks you to decide which version to keep. Understanding branching and merging is critical because it is the mechanism behind every code review, every feature release, and every hotfix in professional development.
Branches are cheap in Git. They are just lightweight pointers to commits, not full copies of your code. This means you can create, switch, and delete branches in milliseconds, encouraging experimentation without risk.
Define Terms
Visual Model
The full process at a glance. Click Start tour to walk through each step.
Branching creates parallel development paths. Merging brings them back together, creating a merge commit with two parents.
Code Example
// Git branching and merging commands
// 1. Create and switch to a new branch
// $ git branch feature-signup
// $ git checkout feature-signup
// Or in one step:
// $ git checkout -b feature-signup
// 2. Make commits on the feature branch
// $ echo "signup form" > signup.html
// $ git add signup.html
// $ git commit -m "Add signup form"
// 3. Switch back to main
// $ git checkout main
// 4. Merge the feature branch into main
// $ git merge feature-signup
// 5. Delete the merged branch (cleanup)
// $ git branch -d feature-signup
// 6. Handling a merge conflict
// $ git merge feature-signup
// CONFLICT in index.html
// Open the file, look for conflict markers:
// <<<<<<< HEAD
// (your main branch version)
// =======
// (feature branch version)
// >>>>>>> feature-signup
// Edit the file to resolve, then:
// $ git add index.html
// $ git commit -m "Resolve merge conflict"
// Simulating branches in JavaScript
class BranchManager {
constructor() {
this.branches = { main: [] };
this.current = "main";
}
createBranch(name) {
// Copy current branch history
this.branches[name] = [...this.branches[this.current]];
}
checkout(name) {
if (!(name in this.branches)) {
throw new Error("Branch not found: " + name);
}
this.current = name;
}
commit(message) {
this.branches[this.current].push(message);
}
merge(sourceBranch) {
const sourceCommits = this.branches[sourceBranch];
const targetCommits = this.branches[this.current];
// Find new commits not in target
const newCommits = sourceCommits.filter(
c => !targetCommits.includes(c)
);
this.branches[this.current].push(...newCommits);
this.branches[this.current].push(
"Merge " + sourceBranch + " into " + this.current
);
}
log() {
return this.branches[this.current];
}
}
const mgr = new BranchManager();
mgr.commit("Initial commit");
mgr.createBranch("feature");
mgr.checkout("feature");
mgr.commit("Add signup form");
mgr.checkout("main");
mgr.merge("feature");
console.log(mgr.log());Interactive Experiment
Try these exercises in a real Git repository:
- Create a new branch called
experiment. Make two commits on it, then switch back tomain. Rungit log --oneline --all --graphto see both branches visually. - Create two branches from
main. Edit the same line in the same file on both branches. Merge one, then try merging the other -- you will encounter a merge conflict. Practice resolving it. - After merging a branch, run
git log --oneline --graphto see the merge commit with two parent lines joining. - Try a fast-forward merge: create a branch from main, add commits, and merge it back without making any new commits on main. Notice that no merge commit is created.
Quick Quiz
Coding Challenge
Implement a `BranchManager` class that simulates Git branching. It should support: `createBranch(name)` to create a new branch from the current branch (throw 'Branch already exists' if it does), `checkout(name)` to switch branches (throw 'Branch not found' if it does not exist), `commit(message)` to add a commit to the current branch, `getCurrentBranch()` to return the current branch name, and `getLog(branchName)` to return an array of commit messages for the given branch.
Real-World Usage
Branching and merging are central to every professional Git workflow:
- Feature branches: Developers create a branch for each feature or bug fix. This isolates work-in-progress from the stable main branch until the feature is complete and reviewed.
- Release branches: Teams create a release branch to stabilize code for deployment while continuing development on main.
- Hotfix branches: When a critical bug is found in production, a hotfix branch lets you patch it immediately without including unfinished features.
- Git Flow and GitHub Flow are popular branching strategies used by teams at companies like GitHub, GitLab, Atlassian, and thousands of open source projects.