Branches and Merging
Branches and Merging
Why branches?
Branches are one of the most powerful concepts in Git. They allow you to work on different features in parallel, without interfering with stable code.
main ●───●───●───────────●───●
\ /
feature/login ●───●───●
Each branch is simply a pointer to a commit. Creating a branch is nearly instantaneous.
Working with branches
Creating and navigating
# View branches
git branch # Local branches
git branch -a # All (local + remote)
# Create a branch
git branch feature/login
# Switch branches
git checkout feature/login
# Or (Git 2.23+)
git switch feature/login
# Create AND switch in a single command
git checkout -b feature/login
# Or
git switch -c feature/login
# Delete a branch
git branch -d feature/login # Only if merged
git branch -D feature/login # Force deletion
Naming conventions
feature/feature-name # New feature
fix/bug-description # Bug fix
hotfix/urgent-fix # Urgent production fix
refactor/refactoring-name # Refactoring
docs/update-readme # Documentation
Merging
Classic merge
# Switch to the target branch
git checkout main
# Merge the feature branch
git merge feature/login
Case 1: Fast-forward
If main has not moved since the branch was created, Git simply moves the pointer forward:
Before:
main ●───●
\
feature ●───●───●
After (fast-forward):
main ●───●───●───●───●
# Force a merge commit (even in fast-forward)
git merge --no-ff feature/login
Case 2: Merge with commit
If main has evolved in parallel, Git creates a merge commit:
Before:
main ●───●───●───●
\
feature ●───●
After:
main ●───●───●───●───M
\ /
feature ●───●────
Resolving conflicts
A conflict occurs when two branches modify the same part of a file.
Anatomy of a conflict
<<<<<<< HEAD
const title = "Welcome";
=======
const title = "Hello!";
>>>>>>> feature/login
- Between
<<<<<<< HEADand=======: the code from the current branch - Between
=======and>>>>>>> feature/login: the code from the incoming branch
Resolving a conflict
# 1. Git reports the conflict during the merge
git merge feature/login
# CONFLICT (content): Merge conflict in src/app.js
# 2. View the conflicting files
git status
# 3. Open the file and choose the correct version
# Remove the markers <<<<<<<, =======, >>>>>>> and keep the right code
const title = "Welcome!";
# 4. Mark as resolved and commit
git add src/app.js
git commit -m "Merge feature/login: resolve title conflict"
Aborting a merge in progress
# If the merge goes wrong, you can abort
git merge --abort
Rebase — rewriting history
Rebase is an alternative to merge that produces a linear history.
Merge vs Rebase
Merge:
main ●───●───●───●───M
\ /
feature ●───●────
Rebase:
main ●───●───●───●
\
feature (rebased) ●'──●'
# Switch to the feature branch
git checkout feature/login
# Rebase onto main
git rebase main
# Then merge (fast-forward)
git checkout main
git merge feature/login
When to use rebase vs merge?
| Situation | Recommendation |
|---|---|
| Update a feature branch with the latest changes from main | git rebase main |
| Integrate a completed feature into main | git merge --no-ff feature |
| Branch shared with other developers | Never rebase |
| Local personal branch | Rebase OK |
Golden rule: never rebase a branch that has been pushed and shared with others.
Cherry-pick — pick a specific commit
# Apply a specific commit from another branch
git cherry-pick abc1234
# Cherry-pick without committing immediately
git cherry-pick --no-commit abc1234
# Useful for:
# - Applying a hotfix across multiple branches
# - Recovering a commit from an abandoned branch
Common workflows
Git Flow
main ●─────────────────●─────────────●
\ / \ /
develop ●───●───●───●────●───●───●──●
\ / \ /
feature/a ●───● ● ●
feature/b
main: production codedevelop: feature integrationfeature/*: feature developmentrelease/*: release preparationhotfix/*: urgent fixes
GitHub Flow (simpler)
main ●───●───●───────●───●
\ /
feature/login ●───●
↑
Pull Request + Review
- Create a branch from
main - Make commits
- Open a Pull Request
- Code review
- Merge into
main
Best practices
- One branch per feature — keep branches short and focused
- Update regularly your feature branch from
main - Resolve conflicts early — the longer you wait, the harder it gets
- Delete merged branches to keep the repository clean
- Use
--no-fffor important merges to preserve the history - Never force push to
main— use Pull Requests