Git 3b 🧩 Basic Branch Commands
3b Basic Branch Commands
Branches are Git’s working unit — you create one for each feature, fix, or experiment, then merge it back when done. The commands that manage branches are the ones you’ll type most often. This chapter covers them systematically: listing, creating, switching, merging, and deleting.
Key point: Most modern Git usage replaces git checkout with git switch for branch changes and keeps git checkout for file restores. switch is clearer and less error-prone — prefer it when you can.
Listing all local branches
The git branch command lists local branches.
git branch
Output:
bugfix/issue-123
* feature/login
main
The asterisk marks the current branch.
Useful options:
| Command | Shows |
|---|---|
git branch | Local branches |
git branch -a | Local + remote-tracking |
git branch -v | Branches with last commit |
git branch -vv | Branches with tracking info |
git branch --merged | Merged into current |
git branch --no-merged | Not merged into current |
git branch --stat | With size/statistics |
git branch -a is the most useful variant — it shows everything at once:
* main
feature/login
remotes/origin/main
remotes/origin/feature/login
Why so many flags:
-ashows remotes,-vshows commit info,--merged/--no-mergedtell you what’s safe to delete. Together they give you the full picture of what branches exist and what they contain.
Creating new branches
There are two ways to create a branch: with git branch (creates but doesn’t switch), or with git checkout -b / git switch -c (creates and switches).
Create without switching:
git branch feature/new-ui
git branch develop
You stay on your current branch. The new one points at the same commit.
Create and switch — checkout:
git checkout -b feature/user-profile
Older syntax. Works everywhere.
Create and switch — switch (modern):
git switch -c feature/user-profile
Newer syntax, clearer intent.
Create from a specific commit:
git branch feature/new-ui abc1234
git switch -c feature/new-feature abc1234
The new branch starts at that commit, not at the current position.
Create from a remote branch:
git branch feature/new-ui origin/main
git switch -c feature/new-feature origin/main
This starts the local branch from the remote’s state, not from your local main.
Why the
-cshortcut matters: Creating a branch without switching is rarely what you want.-ccombines the two steps, which is why it’s the common form.
Switching between branches
Old method — git checkout:
git checkout main
git checkout feature/login
git checkout develop
Works everywhere, but checkout is overloaded — it also restores files.
New method — git switch:
git switch main
git switch feature/login
git switch develop
switch only changes branches. Clearer, safer, less ambiguous.
Why switch is better:
| Aspect | checkout | switch |
|---|---|---|
| Purpose | Branches and files | Branches only |
| Clarity | Ambiguous | Explicit |
| Error messages | Generic | Branch-specific |
| Accidental branch creation | Possible | No |
Switching with options:
# Force switch and reset working directory
git switch --force-create branch-name
# Switch and set upstream tracking
git switch -c branch-name --track origin/branch-name
The --force-create option is destructive — it resets your working directory, discarding uncommitted changes. Use it only when you’re sure.
Why uncommitted changes matter: Git refuses to switch branches if the switch would overwrite uncommitted work. That’s a feature — it protects you. Commit or stash before switching.
Merging branches
git merge combines another branch’s changes into your current branch.
git checkout main
git merge feature/user-profile
You must be on the target branch. git merge feature/user-profile while on main brings the feature branch into main.
Two types of merges:
Fast-forward — happens when the current branch is a direct ancestor of the branch being merged. Git simply moves the branch pointer forward. No merge commit.
Before:
main: A---B---C
feature: \
D
After git merge feature:
main: A---B---C---D
Three-way merge — happens when branches have diverged. Git creates a merge commit with two parents.
Before:
main: A---B---C
feature: \
D---E
After git merge feature:
main: A---B---C---F
\ /
D---E
| Type | When | Result |
|---|---|---|
| Fast-forward | No divergence | Pointer moves |
| Three-way | Branches diverged | Merge commit |
Merge strategies and options:
# Squash all feature commits into one
git merge --squash feature-branch
# Always create a merge commit (no fast-forward)
git merge --no-ff feature-branch
# Use a specific strategy
git merge --strategy-option recursive
Why --no-ff: It preserves the fact that a branch existed. Fast-forward merges lose that context — the history looks flat. --no-ff keeps the branch structure visible.
Why --squash: It collapses all the feature branch’s commits into a single staged change. You then commit once. Useful for cleanup when the feature branch has messy commits.
Why merge types matter: Fast-forward gives clean history; three-way preserves context. Choose based on the workflow — many teams use
--no-ffon shared branches and fast-forward on private ones.
Deleting branches
Safe delete — git branch -d:
git branch -d feature/user-profile
git branch -d bugfix/issue-123
Refuses to delete if the branch isn’t fully merged. This prevents losing unmerged work.
Force delete — git branch -D:
git branch -D feature/user-profile
git branch -D bugfix/issue-123
Deletes regardless of merge state. The unmerged commits become unreachable — and eventually garbage-collected.
Why the two flags:
-dprotects you.-Dis an override for cases where you know the branch’s work is either merged elsewhere or intentionally discarded.
Deleting remote branches:
git push origin --delete feature/user-profile
Alternative syntax:
git push origin :feature/user-profile
Both do the same thing — the colon form means “push nothing to this branch, which deletes it.”
Delete multiple remote branches at once:
git push origin --delete feature/branch1 feature/branch2
Why remote branches need a push: A remote branch lives on the server. Deleting it requires telling the server, which is what
git push origin --deletedoes.
Advanced branch operations
Setting upstream tracking:
# Create a branch tracking a remote branch
git switch -c feature/new-feature origin/main
# Set upstream after creating a branch
git branch --set-upstream-to=origin/feature/new-feature
Once upstream is set, git push and git pull work without arguments.
Renaming branches:
# Rename the current branch
git branch -m new-name
# Rename a specific branch
git branch -m old-name new-name
The -m flag moves (renames) the branch. Simple and safe.
Listing with more detail:
# Last commit info
git branch -v
# Tracking info
git branch -vv
# Statistics
git branch --stat
git branch -vv shows tracking relationships — useful when you’re working with remotes.
Why upstream matters: Without tracking,
git pushneeds a remote and branch name every time. With tracking set,git pushjust works.
Best Practices and Tips
1. Verify before deleting — run git branch -v to check whether a branch is merged. Deleting unmerged work is permanent.
2. Use descriptive names — branch names should say what they contain:
feature/user-login
bugfix/payment-processing
hotfix/critical-security-issue
3. Keep branches small and focused — one feature, one fix per branch. Large branches are hard to review and merge.
4. Regular cleanup — delete merged branches regularly. A repository with 50 stale branches is harder to navigate than one with 5.
5. Prefer git switch over git checkout — clearer intent, better errors, fewer surprises.
Quick Reference
Listing Branches
| Command | Shows |
|---|---|
git branch | Local branches |
git branch -a | Local + remote |
git branch -v | With last commit |
git branch -vv | With tracking |
git branch --merged | Merged into current |
git branch --no-merged | Not merged |
git branch --stat | With statistics |
Creating Branches
| Command | Action |
|---|---|
git branch NAME | Create only |
git checkout -b NAME | Create + switch |
git switch -c NAME | Create + switch (modern) |
git branch NAME COMMIT | From specific commit |
git switch -c NAME origin/BRANCH | From remote |
Switching Branches
| Command | Action |
|---|---|
git checkout NAME | Switch (old) |
git switch NAME | Switch (modern) |
git switch --force-create NAME | Force switch |
git switch -c NAME --track origin/NAME | Track remote |
Merging Branches
| Command | Action |
|---|---|
git merge NAME | Merge into current |
git merge --no-ff NAME | Always merge commit |
git merge --squash NAME | Squash into one commit |
git merge --strategy-option recursive | Use strategy |
Deleting Branches
| Command | Action |
|---|---|
git branch -d NAME | Safe delete |
git branch -D NAME | Force delete |
git push origin --delete NAME | Delete remote |
git push origin :NAME | Same, alternative |
git push origin --delete B1 B2 | Multiple |
Advanced
| Command | Action |
|---|---|
git branch -m NEW | Rename current |
git branch -m OLD NEW | Rename specific |
git branch --set-upstream-to=origin/NAME | Set tracking |
Merge Types
| Type | When | Result |
|---|---|---|
| Fast-forward | Linear | No merge commit |
| Three-way | Diverged | Merge commit |
| Squash | Manual | Single commit |
| No-FF | Forced | Always merge commit |
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
| Uncommitted changes | Switch fails | Commit or stash first |
| Wrong target for merge | Wrong branch updated | Check git branch first |
| Delete unmerged branch | Lost work | Use -d unless sure |
| Force switch | Loses changes | Avoid unless intended |
Ambiguous checkout | Wrong action | Use switch and restore |
| No upstream set | git push needs args | git branch --set-upstream-to |
| Stale branches | Clutter | Delete merged ones |
| Merging without testing | Broken main | Test before merge |
Real-World Examples
1. List local branches
git branch
Shows branches with * on current.
2. List all branches
git branch -a
Includes remotes.
3. List with tracking
git branch -vv
Shows upstream relationships.
4. Create a branch
git switch -c feature/login
Create and switch.
5. Create without switching
git branch feature/login
Stays on current branch.
6. Switch branches
git switch main
Modern syntax.
7. Merge a branch
git switch main
git merge feature/login
Target the destination, then merge.
8. Merge without fast-forward
git merge --no-ff feature/login
Forces a merge commit.
9. Delete a merged branch
git branch -d feature/login
Safe delete.
10. Delete a remote branch
git push origin --delete feature/login
Removes it from the remote.
11. Rename a branch
git branch -m new-name
Renames the current branch.
12. Set upstream tracking
git branch --set-upstream-to=origin/feature/login
Enables bare git push and git pull.
13. Find merged branches
git branch --merged
Safe to delete.
14. Find unmerged branches
git branch --no-merged
Do not delete yet.
15. Clean up many branches
git branch --merged | grep -v main | xargs git branch -d
Delete all merged branches except main.
Visual: Listing Branches
┌──────────────────────────────────────────────┐
│ git branch │
│ │
│ bugfix/issue-123 │
│ * feature/login ← current branch │
│ main │
│ │
├──────────────────────────────────────────────┤
│ git branch -a │
│ │
│ * main │
│ feature/login │
│ remotes/origin/main │
│ remotes/origin/feature/login │
│ │
└──────────────────────────────────────────────┘
Visual: Create, Switch, Merge
┌──────────────────────────────────────────────┐
│ git switch -c feature/login │
│ │
│ main ──► A ──► B │
│ \ │
│ feature/login (HEAD) │
│ │
├──────────────────────────────────────────────┤
│ Work and commit on feature │
│ │
│ main ──► A ──► B │
│ \ │
│ C ──► D │
│ ▲ │
│ HEAD │
│ │
├──────────────────────────────────────────────┤
│ git switch main && git merge feature/login │
│ │
│ main ──► A ──► B ──► C ──► D │
│ ▲ │
│ HEAD │
│ │
└──────────────────────────────────────────────┘
Visual: Merge Types
┌──────────────────────────────────────────────┐
│ Fast-forward │
│ │
│ main: A ──► B │
│ feature: A ──► B ──► C ──► D │
│ │
│ After merge: │
│ main: A ──► B ──► C ──► D │
│ │
│ No merge commit — pointer moves forward │
│ │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ Three-way merge │
│ │
│ main: A ──► B ──► E ──► F │
│ feature: A ──► B ──► C ──► D │
│ │
│ After merge: │
│ main: A ──► B ──► E ──► F ──► M │
│ \ / │
│ C ──► D ──┘ │
│ │
│ M is a merge commit (two parents) │
│ │
└──────────────────────────────────────────────┘
Visual: Delete Safety
┌──────────────────────────────────────────────┐
│ git branch -d feature/login │
│ │
│ Merged? │
│ │ │
│ yes│ no │
│ ▼ ▼ │
│ deleted refuses │
│ │
│ Safe — protects unmerged work │
│ │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ git branch -D feature/login │
│ │
│ Deletes regardless of merge status │
│ │
│ ⚠️ Unmerged commits become unreachable │
│ │
└──────────────────────────────────────────────┘
Visual: checkout vs switch
┌──────────────────────────────────────────────┐
│ git checkout │
│ │
│ Branches: git checkout feature │
│ Files: git checkout -- file.txt │
│ Create: git checkout -b new │
│ │
│ Overloaded — one command, many meanings │
│ │
└──────────────────────────────────────────────┘
┌──────────────────────────────────────────────┐
│ git switch │
│ │
│ Branches: git switch feature │
│ Create: git switch -c new │
│ │
│ Single purpose — switching branches only │
│ │
└──────────────────────────────────────────────┘
Summary
| Command | Purpose |
|---|---|
git branch | List local branches |
git branch -a | List local + remote |
git branch -v | With last commit |
git branch -vv | With tracking |
git branch NAME | Create without switching |
git switch -c NAME | Create and switch |
git switch NAME | Switch branches |
git merge NAME | Merge into current |
git branch -d NAME | Safe delete |
git branch -D NAME | Force delete |
git push origin --delete NAME | Delete remote |
git branch -m NEW | Rename |
Key takeaways:
git branchlists local branches;-aincludes remotes,-vshows commits,-vvshows trackinggit branch NAMEcreates a branch but doesn’t switch;git switch -c NAMEdoes bothgit switchis the modern replacement forgit checkoutwhen changing branchesgit mergebrings another branch into your current one — you must be on the target- Fast-forward merges just move the pointer; three-way merges create a merge commit
- Use
--no-ffto force a merge commit and preserve branch context - Use
--squashto collapse a feature branch into a single commit git branch -drefuses to delete unmerged work;-Dforces it- Remote branches are deleted with
git push origin --delete NAME git branch -mrenames branches- Set upstream tracking so
git pushandgit pullwork without arguments - Prefer
git switchovergit checkout— clearer and safer - Keep branches small, focused, and named by purpose
- Verify before deleting — unmerged branches lose work permanently
Remember: Branches are the working unit of Git. Create one per task, switch between them freely, merge when ready, delete when done. Prefer switch for changing branches and keep checkout for restoring files. Use -d for safe deletes, -D when you know what you’re doing, and --no-ff when you want a merge commit. Master these commands and every Git workflow becomes manageable.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!