By day 8 of your Git and GitHub journey, you've committed code and pushed it upstream. Now it's time to work like the professionals do: creating isolated branches, collaborating without stepping on each other's toes, and merging changes back in a controlled way. Git branching basics: a Git & GitHub guide for developers covers the everyday commands that let teams ship features, fix bugs, and experiment safely on the same repository.
Why branches matter in professional workflows
Imagine your team's main branch is the single source of truth for production code. If every developer pushed directly to main, you'd have half-finished features, broken tests, and deploy disasters every single day. Branches solve this by letting each person work in isolation. A feature branch for login flows, another for payment integration, another for database migrations—all running in parallel, all protected from main until they're ready.
In real projects, branches also enforce code review discipline. On platforms like GitHub, you can't merge a branch to main without approval. Your CI pipeline runs tests. Your team reviews the code. Only then does it land in production. That's the professional model, and it starts with understanding how to create and manage branches locally.
Creating and switching branches with git switch
The modern way to create and switch to a new branch is git switch -c (the -c flag stands for "create"). This is clearer than the older git checkout -b syntax, though both work.
Let's say you're starting work on a login feature. You'd run:
git switch -c feature/loginThis command does two things: it creates a new branch called feature/login and immediately switches you onto it. Your HEAD now points to this branch, and any commits you make will be recorded here, not on main.
A few naming conventions help keep teams organized:
feature/for new features (e.g.,feature/payment-gateway)bugfix/for bug fixes (e.g.,bugfix/cart-crash-on-mobile)hotfix/for urgent production fixes (e.g.,hotfix/database-connection-leak)refactor/for code improvements without behavior changes (e.g.,refactor/auth-service)docs/for documentation updates
Using prefixes makes branch history readable and helps automation tools route branches to the right reviewers or deploy pipelines.
If you already have a branch and just need to switch to it (without creating), use git switch without the -c flag:
git switch feature/loginYou can only switch if your working directory is clean (no uncommitted changes that would conflict). If you have uncommitted work, either commit it, stash it with git stash, or discard it with git restore.
Listing branches and tracking information
After a few weeks of development, you'll have many branches. The git branch command lists them. The basic form shows local branches:
git branchOutput might look like:
bugfix/old-bug
feature/login
feature/payments
* main
refactor/databaseThe asterisk marks your current branch. But this doesn't show you which branches are tracking upstream (on GitHub or your Git server). That's where -vv comes in:
git branch -vvOutput:
bugfix/old-bug a1b2c3d old commit message
feature/login f4e5d6c [origin/feature/login] latest commit message
feature/payments g7h8i9j [origin/feature/payments: ahead 3] commit here
* main k0l1m2n [origin/main] up to date
refactor/database o3p4q5r [origin/refactor/database: behind 2] earlier commitThe -vv output tells you:
- The latest commit hash on each branch
- The commit message
- Which remote branch it's tracking (if any)
- Whether you're ahead, behind, or in sync with the remote
This is invaluable when coordinating with your team. If feature/login shows it's tracking origin/feature/login, your local and remote are in sync. If feature/payments is "ahead 3," you have 3 commits not yet pushed.
To remove branches you no longer need from your view, use git branch -d branch-name (more on this below).
Merging branches to bring changes into main
Once your feature is complete, tested, and approved, you merge it back into main. The standard workflow is:
- Switch to main
- Pull the latest version from GitHub
- Merge your feature branch
- Push the result back to GitHub
Here's the concrete sequence:
git switch main
git pull origin main
git merge feature/login
git push origin mainAfter step 2, your local main is up to date with GitHub. Step 3 applies all commits from feature/login into your current branch (main). If there are no conflicts, Git creates a merge commit that records the integration. Step 4 pushes main back to GitHub.
Fast-forward vs. three-way merges
Git uses different merge strategies depending on history. If your feature branch was created from an older commit on main and main has moved ahead, Git performs a three-way merge: it finds the common ancestor, compares both branches, and creates a new merge commit. If your feature branch is directly ahead of main (no intervening commits on main since you branched), Git performs a fast-forward merge: it just moves the main pointer forward to your feature commit. Both are safe; the difference is in the resulting history.
Some teams prefer to always create an explicit merge commit, even on fast-forward merges, for clearer history:
git merge --no-ff feature/loginThe --no-ff flag (no fast-forward) forces Git to create a merge commit regardless.
Handling merge conflicts
If you and a colleague both edited the same lines in the same file, Git can't automatically decide which changes to keep. It stops and asks you to resolve the conflict.
Git marks conflicts in your files like this:
<<<<<<< HEAD
password: hashedPassword,
=======
password: password,
>>>>>>> feature/loginYou edit the file, keeping the version you want (or both, restructured), then:
git add conflicted-file.js
git commit -m "Resolve merge conflict in auth service"This completes the merge. In larger projects, conflicts are often resolved in a pull request on GitHub, where both versions are visible side-by-side.
Deleting merged branches
Once a branch is merged, it's typically no longer needed. Leaving old branches around clutters your branch list and can confuse team members. Delete them with:
git branch -d feature/loginThe -d flag (delete) only works if the branch is fully merged into your current branch. If you try to delete an unmerged branch, Git refuses:
error: The branch 'feature/login' is not fully merged.This protection prevents accidental loss of work. If you're absolutely sure you want to discard an unmerged branch, use -D (uppercase):
git branch -D feature/loginYou should also delete the remote branch on GitHub so the repository stays clean:
git push origin --delete feature/loginOr, if you've already deleted the local branch and the remote branch is still there (stale tracking branch), prune it with:
git fetch --pruneThis removes local references to branches that no longer exist on the remote.
Common mistakes
Merging into the wrong branch
You meant to merge into main but accidentally merged into develop. You were on develop and ran git merge feature/login, and now develop has commits it shouldn't. Use git reset to undo:
git reset --hard HEAD~1This rewinds develop by one commit (the merge commit). Make sure you're on the right branch before merging next time. A good habit: always confirm your current branch before running a merge.
Deleting a branch that wasn't pushed
You created a branch, made commits, then deleted it locally without pushing to GitHub. The commits still exist in Git's reflog for a while, but the branch is gone from your daily view. Always push feature branches to GitHub before deletion, or at least confirm they're merged into main first.
Switching branches with uncommitted changes
You're on feature/login, you made edits, and you switch to main without committing or stashing. Git either refuses (if there's a conflict) or silently carries your changes to main (which is confusing). Always commit or stash before switching. If you accidentally switched, use git stash to capture your work, switch back to the correct branch, and re-apply it:
git stash
git switch feature/login
git stash popForce-pushing a shared branch
Never use git push --force on a branch that others are working on. Force-push rewrites history and can destroy your teammates' commits. It's okay to force-push your own feature branch before the first code review, but once others have branched from it or are reviewing, don't rewrite it.
Key takeaways
- Use
git switch -c branch-nameto create and move to a new branch in one command. Follow naming conventions likefeature/,bugfix/, andrefactor/for clarity. - Run
git branch -vvto see which branches track remote versions and whether you're ahead or behind. - Merge branches with
git switch main,git pull origin main,git merge feature-branch, andgit push origin main. Watch for merge conflicts and resolve them by editing the marked sections. - Delete merged branches locally with
git branch -dand remotely withgit push origin --deleteto keep the repository tidy. - Always commit or stash changes before switching branches. Always confirm your current branch before merging. Never force-push shared branches.
- Branches isolate work, enable parallel development, and enforce code review discipline—they're the foundation of professional Git workflows.






Comments
Loading comments…