Skip to main content

Git Branching and Merging

·1275 words·6 mins
Linux Learning Lab
Author
Linux Learning Lab
Writing about code, tools, and workflows.
git-essentials - This article is part of a series.
Part 2: This Article

What Are Branches?
#

A branch is an independent line of development. When you create a branch, you get a copy of the codebase where you can make changes without affecting the main branch. When the work is ready, you merge it back.

main:      A---B---C
                    \
feature:             D---E---F

Branches let you:

  • Work on a feature without breaking the stable code
  • Have multiple people working on different things simultaneously
  • Experiment freely — throw the branch away if it doesn’t work out

Viewing Branches
#

# List local branches (* marks current)
git branch

# List all branches (including remote)
git branch -a

# Show which branch you're on
git branch --show-current

# List branches with last commit info
git branch -v

Creating Branches
#

# Create a new branch
git branch feature/login

# Create and switch to it immediately
git checkout -b feature/login

# Modern alternative (Git 2.23+)
git switch -c feature/login

The branch starts from wherever you are (usually the latest commit on main).

Branch from a specific point
#

# Branch from a tag
git checkout -b hotfix/v1.2.1 v1.2.0

# Branch from a specific commit
git checkout -b recovery abc1234

Switching Branches
#

# Classic
git checkout feature/login

# Modern (Git 2.23+)
git switch feature/login

# Switch back to previous branch
git checkout -
git switch -

Important: Switching branches changes the files in your working directory. Uncommitted changes come with you if they don’t conflict — otherwise Git will refuse to switch until you commit or stash them.

Branch Naming Conventions
#

Good branch names are descriptive and categorized:

PatternUse forExample
feature/New functionalityfeature/user-auth
fix/Bug fixesfix/login-timeout
hotfix/Urgent production fixeshotfix/security-patch
refactor/Code restructuringrefactor/database-layer
docs/Documentation changesdocs/api-readme

Keep names lowercase, use hyphens not spaces, and be specific:

# Good
git checkout -b feature/add-password-reset
git checkout -b fix/null-pointer-on-empty-input

# Bad
git checkout -b stuff
git checkout -b my-branch
git checkout -b test

Merging
#

Merging combines the work from one branch into another.

Basic merge
#

# Switch to the branch you want to merge INTO
git checkout main

# Merge the feature branch into main
git merge feature/login

Fast-forward merge
#

When the target branch hasn’t changed since you branched off, Git just moves the pointer forward:

Before:
main:      A---B---C
                    \
feature:             D---E

After (git merge feature):
main:      A---B---C---D---E

No merge commit is created — the history stays linear.

Three-way merge
#

When both branches have new commits, Git creates a merge commit:

Before:
main:      A---B---C---G---H
                    \
feature:             D---E---F

After (git merge feature):
main:      A---B---C---G---H---M
                    \         /
feature:             D---E---F

M is the merge commit that ties the two histories together.

No-fast-forward merge
#

Force a merge commit even when fast-forward is possible — preserves branch history:

git merge --no-ff feature/login

This is useful when you want the branch grouping visible in history.

Merge Conflicts
#

Conflicts happen when both branches modified the same part of the same file. Git can’t decide which version to keep, so it asks you.

What a conflict looks like
#

git merge feature/login
# CONFLICT (content): Merge conflict in src/auth.js
# Automatic merge failed; fix conflicts and then commit the result.

The conflicted file contains markers:

function getUser(id) {
<<<<<<< HEAD
    return database.findById(id);
=======
    return cache.get(id) || database.findById(id);
>>>>>>> feature/login
}
MarkerMeaning
<<<<<<< HEADStart of your current branch’s version
=======Divider between the two versions
>>>>>>> feature/loginEnd of the incoming branch’s version

Resolving conflicts
#

  1. Open the file and decide what the final version should be
  2. Remove the conflict markers
  3. Stage the resolved file
  4. Commit
// Resolved — keeping the improved version
function getUser(id) {
    return cache.get(id) || database.findById(id);
}
git add src/auth.js
git commit -m "Merge feature/login: resolve auth.js conflict"

Abort a merge
#

If you want to back out entirely:

git merge --abort

This resets everything to before you ran git merge.

Check for conflicts before merging
#

# Dry run — see if it would conflict
git merge --no-commit --no-ff feature/login
git merge --abort  # undo the test

Deleting Branches
#

After merging, clean up:

# Delete a merged branch
git branch -d feature/login

# Force delete an unmerged branch (careful — loses work)
git branch -D feature/experiment

Delete a remote branch
#

git push origin --delete feature/login

Remote Branches
#

Push a branch to remote
#

# First push — set up tracking
git push -u origin feature/login

# Subsequent pushes
git push

Track a remote branch
#

# Fetch all remote branches
git fetch

# Create a local branch tracking a remote one
git checkout -b feature/login origin/feature/login

# Or the shorthand (if branch name matches)
git checkout feature/login

See what remote branches exist
#

git branch -r

Keeping Branches Up to Date
#

Your feature branch may fall behind main while you work. Sync it:

Merge main into your branch
#

git checkout feature/login
git merge main

This creates a merge commit in your feature branch.

Rebase onto main (alternative)
#

git checkout feature/login
git rebase main

This replays your commits on top of the latest main — keeps history linear but rewrites commits. Don’t rebase branches that others are working on.

Practical Workflows
#

Feature branch workflow
#

# Start a feature
git checkout main
git pull
git checkout -b feature/shopping-cart

# Work on it
# ... edit files ...
git add .
git commit -m "Add cart item model"
# ... more work ...
git commit -m "Add cart API endpoints"

# Keep up with main
git merge main

# Push for review
git push -u origin feature/shopping-cart

# After review, merge to main
git checkout main
git merge feature/shopping-cart
git push
git branch -d feature/shopping-cart

Hotfix workflow
#

# Branch from main (or the release tag)
git checkout -b hotfix/fix-payment-crash main

# Make the fix
git commit -am "Fix null pointer in payment processing"

# Merge back to main
git checkout main
git merge hotfix/fix-payment-crash
git push

# Clean up
git branch -d hotfix/fix-payment-crash

Exploring an idea
#

# Try something risky
git checkout -b experiment/new-algorithm

# ... work on it ...

# Didn't work out — throw it away
git checkout main
git branch -D experiment/new-algorithm

Viewing Branch History
#

# Graph showing all branches
git log --oneline --graph --all

# Commits on feature that aren't on main
git log main..feature/login --oneline

# Commits on main that aren't in feature (what you're missing)
git log feature/login..main --oneline

# Which branches contain a specific commit
git branch --contains abc1234

# Which branches are merged into main
git branch --merged main

# Which branches are NOT merged into main
git branch --no-merged main

Quick Reference
#

TaskCommand
Create branchgit checkout -b name
Switch branchgit checkout name or git switch name
List branchesgit branch
Merge branchgit merge name
Delete branchgit branch -d name
Push branchgit push -u origin name
Delete remote branchgit push origin --delete name
Abort mergegit merge --abort
Switch to previousgit checkout -
Show graphgit log --oneline --graph --all

Best Practices
#

  • Keep branches short-lived — merge or delete within days, not weeks
  • Pull main often into your feature branch to avoid painful merge conflicts later
  • Use descriptive names with category prefixes (feature/, fix/, docs/)
  • Delete branches after merging — stale branches clutter the repo
  • Don’t commit directly to main — use branches even for small changes on shared repos
  • If a merge conflict scares you, use git merge --abort to reset and think about it
  • Use git log --graph to visualize what happened — it’s the fastest way to understand complex branch history
  • Prefer --no-ff merges on shared repos so branch history is preserved in the log
git-essentials - This article is part of a series.
Part 2: This Article