Git Branching & Merging — Complete Practical Guide
Git branches let you work on features, fixes, or experiments in isolation without disrupting the main codebase — think of them as parallel universes where you can test changes safely before merging them back.
What You’ll Learn
By the end of this tutorial, you’ll create and switch branches, merge changes using fast-forward and three-way merges, resolve merge conflicts, use rebase for a clean history, and cherry-pick individual commits between branches.
Why Branching Matters
Branching is what makes Git powerful for teams. Without branches, everyone edits the same code simultaneously — chaos. With branches, multiple developers build features in parallel, and only reviewed, tested code reaches the main branch. DodaTech uses feature branching for every product: Doda Browser releases, DodaZIP updates, and Durga Antivirus Pro signature updates all go through branch-based workflows.
Security note: Understanding Git Branching helps build more secure applications — a core principle at DodaTech, where tools like Durga Antivirus Pro and Doda Browser rely on solid implementation practices.
Branching Learning Path
flowchart LR
A[Git Basics] --> B[Branching & Merging]
B --> C[Remote Repositories]
C --> D[Undoing Changes]
D --> E[Advanced Git]
style B fill:#3b82f6,stroke:#fff,color:#fff
git init, git add, git commit, and git status. Review Git first if needed.How Branching Works — The Parallel Universes Analogy
Imagine your codebase is a book. The main branch is the published edition. Creating a branch is like writing a draft chapter in a parallel notebook:
- You can write freely in the draft without messing up the published book
- Multiple writers can each have their own draft
- When a draft is ready, you merge it into the published book
- Sometimes two drafts change the same sentence — that’s a merge conflict
gitGraph
commit id:"A"
commit id:"B"
branch feature
checkout feature
commit id:"C"
commit id:"D"
checkout main
merge feature
commit id:"E"
Why create a branch? Because you don’t want half-finished work on main. If a colleague pulls main and finds broken code, they can’t work. Branches keep main clean and deployable at all times.
Creating & Switching Branches
# Create a branch (stays on current branch)
git branch feature-navbar
# Switch to it
git checkout feature-navbar
# Or do both at once (most common)
git checkout -b feature-navbar
# Modern alternative (Git 2.23+)
git switch -c feature-navbar # create + switch
git switch main # switch existingLine-by-line explanation:
git branch feature-navbar— creates a new pointer at your current commit. You’re still onmaingit checkout feature-navbar— moves your working directory to that branchgit checkout -b feature-navbar— creates AND switches in one command. You’ll use this 90% of the timegit switch— newer, more intuitive command.-cmeans “create”
git switch instead of git checkout for branch operations. Reserve git checkout for restoring files or older Git versions.Listing Branches
git branch # local branches (* = current branch)
git branch -a # all branches (including remote-tracking ones)
git branch -r # remote branches only
git branch -v # show last commit on each branchOutput:
* main
feature-navbar
remotes/origin/mainThe * tells you which branch you’re currently on. Always check before making changes!
Merging — Bringing Changes Together
Merging takes changes from one branch and applies them to another. There are two types:
Fast-Forward Merge
When the target branch hasn’t diverged — main hasn’t moved since you branched off:
git checkout main
git merge feature-navbar
# Updating a1b2c3d..d4e5f6g
# Fast-forwardAnalogy: You’re catching up to someone who ran ahead — just walk forward to where they are. No new junction created.
Three-Way Merge
When both branches have new commits — Git must combine two histories:
git checkout main
git merge feature-navbar
# Merge made by the 'ort' strategy.Git creates a merge commit that has two parents — one from each branch.
gitGraph
commit id:"A"
commit id:"B"
branch feature
checkout feature
commit id:"C"
checkout main
commit id:"D"
checkout feature
commit id:"E"
checkout main
merge feature
Merge with –no-ff
Forces a merge commit even when fast-forward is possible — useful for preserving branch history visually:
git merge --no-ff feature-navbarWhy use it? When you look at history later, you can see clearly: “here was a feature branch.” Without it, the commits look like they were all done on main in sequence.
Merge Conflicts
Conflicts happen when two branches modify the same lines of the same file:
git merge feature-navbar
# Auto-merging index.html
# CONFLICT (content): Merge conflict in index.htmlGit marks the conflict in the file:
<<<<<<< HEAD
<title>My Site</title>
=======
<title>My Awesome Site</title>
>>>>>>> feature-navbarUnderstanding the markers:
<<<<<<< HEAD— the start of the conflict, showing your version (current branch)=======— divides your version from the incoming version>>>>>>> feature-navbar— end of conflict, showing their version
Resolution Steps
- Edit the file — keep your version, their version, or a mix of both
- Remove the conflict markers — delete
<<<<<<<,=======,>>>>>>> - Stage and commit:
git add index.html
git commit
# Git opens a pre-filled merge commit message; save and quitConflict Resolution Tools
# See both versions side by side
git mergetool # opens configured merge tool (vimdiff, VS Code, etc.)
# Abort the merge entirely (restart from before)
git merge --abortRebase — Cleaner History
Rebase replays your commits on top of another branch, creating a linear history:
git checkout feature-navbar
git rebase mainBefore rebase:
D---E feature
/
A---B---C mainAfter rebase:
D'---E' feature
/
A---B---C mainD' and E' are new commits with the same changes but new hashes. The history looks like you started working after C.
Why rebase instead of merge? If you merge main into your feature branch repeatedly, you get a tangled history with many merge commits. Rebase keeps it clean — linear and readable.
Interactive Rebase — Squash, Reword, Reorder
Powerful for cleaning up commits before pushing:
git rebase -i HEAD~3 # last 3 commits
# Opens editor with:
# pick a1b2c3d Fix header
# pick d4e5f6g Add dark mode
# pick 7a8b9c0 Fix typoCommands you can use:
pick— keep the commit as-issquash— combine with the previous commit (and merge messages)reword— change the commit messageedit— modify the commit contentdrop— remove the commit entirely
Analogy: Interactive rebase is like editing a photo album — you can remove bad photos, combine similar ones, and rewrite captions before showing it to anyone.
Cherry-Pick — Selective Commits
Copy a specific commit from another branch without merging the whole branch:
git cherry-pick a1b2c3d # applies that commit's changes here
# Multiple commits
git cherry-pick a1b2c3d d4e5f6g
# Stage changes without committing
git cherry-pick --no-commit a1b2c3dWhen to use it: A bug fix was committed on feature-x but you need it on main now. Cherry-pick just that fix instead of merging the entire unfinished feature.
Branching Workflows
Feature Branch Workflow (Most Common)
git checkout -b feature-login # create feature branch
# ... work, commit, work, commit ...
git checkout main
git pull # get latest main
git merge feature-login # merge (or create PR on GitHub)
git branch -d feature-login # delete local branchGit Flow (Complex, for releases)
flowchart LR
main --> develop
develop --> feature1
develop --> feature2
develop --> release
release --> main
main --> hotfix
hotfix --> main
hotfix --> develop
Git Flow uses develop as the integration branch, release branches for preparation, and hotfix branches for urgent production fixes. It’s heavy but structured — best for projects with scheduled releases.
Common Mistakes
1. Rebasing shared branches
Rebasing a branch others have pulled rewrites history. When they pull again, Git sees entirely different commits. The golden rule: only rebase before you push.
2. Rushing through conflict resolution
Blindly keeping one side or the other without understanding both changes. You might delete important code. Always check the merged result — run tests — before committing.
3. Forgetting to switch before creating a branch
git branch new-feature creates it from your current branch. If you’re on an old branch, new-feature starts from there, not from main. Always verify with git branch first.
4. Leaving stale branches everywhere
Old branches clutter git branch -a output. Delete merged branches with git branch -d <branch>. Use git branch -D <branch> to force-delete unmerged branches you’re sure about.
5. Using git merge when rebase is cleaner
To keep your feature branch up to date with main, git rebase main creates a linear history without merge commits. Use rebase for local feature branches; use merge for integrating into shared branches.
6. Cherry-picking without understanding implications
Cherry-pick creates a new commit with a new hash — even if the change is identical. The same edit can appear multiple times in history, which gets confusing during later merges.
Practice Questions
1. What is the difference between a fast-forward merge and a three-way merge?
Answer: Fast-forward happens when main hasn’t diverged — Git just moves the pointer forward. Three-way merge happens when both branches have new commits, requiring a merge commit to join the histories.
2. How do you resolve a merge conflict?
Answer: Edit the file to remove conflict markers (<<<<<<<, =======, >>>>>>>), keep the correct version, then git add the file and git commit.
3. When should you use git rebase instead of git merge?
Answer: Use rebase to keep a linear history when updating a local feature branch with changes from main. Never rebase commits that others have already pulled.
4. What does git cherry-pick a1b2c3d do?
Answer: It takes the changes from commit a1b2c3d on another branch and applies them as new changes to your current branch.
Challenge
Create a repo with two branches that modify the same line of the same file. Merge them, resolve the conflict, then use git log --graph to see the resulting history. Now recreate the scenario and use rebase instead — observe how the history differs.
FAQ
Try It Yourself
Simulate a real team workflow:
# 1. Create and switch to a feature branch
git checkout -b feature-footer
# 2. Make changes
echo "<footer>Copyright 2026</footer>" >> index.html
git add index.html
git commit -m "Add footer to index page"
# 3. Switch back to main and make a conflicting change
git checkout main
echo "<footer>All rights reserved</footer>" >> index.html
git add index.html
git commit -m "Update footer text on main"
# 4. Merge — experience a conflict
git merge feature-footer
# CONFLICT in index.html
# 5. Resolve — edit index.html to keep one footer, remove markers
git add index.html
git commit -m "Resolve footer merge conflict"
# 6. Clean up
git branch -d feature-footer
git log --oneline --graphWhat’s Next
Now that you can branch and merge, connect to the world with remotes:
| Topic | Description |
|---|---|
| https://tutorials.dodatech.com/devops/git/git-remote/ | Push to GitHub, pull requests, SSH keys |
| https://tutorials.dodatech.com/devops/git/git-undo/ | Fix mistakes with reset, revert, stash |
| https://tutorials.dodatech.com/devops/git/git-advanced/ | Tags, hooks, submodules, signing |
Related topics to explore:
- Git Overview
- DevOps Best Practices
- AWS CodeCommit & CI/CD
What’s Next
Congratulations on completing this Git Branching tutorial! Here’s where to go from here:
- Practice daily — Consistency is more important than long study sessions
- Build a project — Apply what you learned by building something real
- Explore related topics — Check out other tutorials in the same category
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro