A Practical Git Branching Workflow for Beginners
Stop committing everything to main. Learn a simple, team-friendly branching workflow with feature branches, pull requests and clean merges.
On this page
When you first learn Git, it's natural to commit everything straight to main. That works until you need to fix a bug halfway through a feature, or a teammate pushes changes that collide with yours.
Branches solve this. In this guide you'll learn a simple workflow used by teams of every size: create a branch for each piece of work, commit freely, then merge it back when it's ready.
What a branch really is#
A branch in Git is just a movable pointer to a commit. Creating one is instant and costs almost nothing, because Git doesn't copy your files. When you make a new commit, the branch you're on moves forward to point at it.
Here, feature/login branches off main after commit C and gets two commits of its own, D and E. Work on one branch doesn't touch the other until you merge, which creates the merge commit M.
The workflow at a glance#
- Update your local
main. - Create a feature branch.
- Commit your work in small steps.
- Push the branch and open a pull request.
- Keep the branch up to date with
main. - Merge, then delete the branch.
Let's walk through each step.
Step 1: Start from an up-to-date main#
git switch main
git pull origin maingit switch (Git 2.23+) is the modern, clearer alternative to git checkout for changing branches.
Step 2: Create a feature branch#
git switch -c feature/login-formThe -c flag creates the branch and switches to it in one go. Use descriptive, prefixed names so everyone can tell what a branch is for:
| Prefix | Use it for | Example |
|---|---|---|
feature/ |
New functionality | feature/login-form |
fix/ |
Bug fixes | fix/password-reset-email |
docs/ |
Documentation | docs/api-examples |
refactor/ |
Code improvements with no behaviour change | refactor/user-service |
Step 3: Commit in small, meaningful steps#
Make a change, review it, then commit:
git status # what changed?
git diff # review the exact changes
git add src/login.js # stage specific files
git commit -m "Add login form markup and validation"Write commit messages for your future self
Use the imperative mood ("Add validation", not "Added validation") and describe what changed and why, not how. A good test: your message should complete the sentence "If applied, this commit will…"
Step 4: Push and open a pull request#
The first time you push a new branch, tell Git which remote branch it should track:
git push -u origin feature/login-form-u sets the upstream, so afterwards a plain git push is enough. On GitHub, GitLab or Bitbucket you'll now see a prompt to open a pull request (called a merge request on GitLab). This is where teammates review your code, leave comments and run automated tests before anything reaches main.
Step 5: Keep your branch up to date#
If main moves on while you work, bring those changes into your branch so you resolve conflicts early and in small pieces:
git switch main
git pull origin main
git switch feature/login-form
git merge mainSome teams prefer git rebase main instead of git merge main. It replays your commits on top of the latest main for a straight-line history. Both are valid, so follow your team's convention.
Never rebase shared history
Rebasing rewrites commits. Only rebase branches that nobody else has based work on. Otherwise you'll create painful conflicts for your teammates.
Resolving a merge conflict#
A conflict happens when two branches change the same lines. Git pauses and marks the file:
<<<<<<< HEAD
const MAX_ATTEMPTS = 5;
=======
const MAX_ATTEMPTS = 3;
>>>>>>> mainThe HEAD section is your branch's version and the bottom section comes from main. Edit the file to keep the correct version, delete the markers, then finish the merge:
git add src/config.js
git commitStep 6: Merge and clean up#
Once the pull request is approved, merge it through your hosting platform. Then tidy up locally:
git switch main
git pull origin main
git branch -d feature/login-formgit branch -d refuses to delete a branch that hasn't been merged, so it's a safe default. If your team uses squash merges, Git may not recognise the branch as merged. Once you've confirmed the pull request was merged, git branch -D forces the deletion.
Handy commands to remember#
git branch # list local branches
git branch -a # include remote branches
git log --oneline --graph --all # visualise history
git switch - # jump back to the previous branch
git stash # shelve uncommitted changes temporarily
git stash pop # bring them backRecap#
- A branch is a lightweight pointer, so create them freely.
- One branch per feature or fix keeps
mainalways deployable. - Commit in small steps, write clear messages and open a pull request for review.
- Merge
maininto your branch regularly to avoid giant conflicts. - Delete branches after merging to keep your repository tidy.
Adopt this workflow even on solo projects. It builds habits that make joining a team effortless.