Git Workflow Guide: Branching, Merging, and Team Collaboration
Master Git branching strategies, commit best practices, rebasing vs. merging, and the workflows used by professional engineering teams.
Git is the foundation of every modern software team's workflow. Yet many developers use only commit, push, and pull — leaving behind the features that make collaborative development smooth and conflict-free. This guide covers the branching strategies, commit practices, and everyday commands used by professional teams.
The core mental model
Git is a directed acyclic graph of snapshots (commits). Each commit points to its parent(s). Branches are simply named pointers to commits — lightweight and cheap to create.
main: A → B → C → D
feature: C → E → F
Branching doesn't copy files — it just creates a new pointer. That's why creating a branch takes milliseconds regardless of repository size.
Branching strategies
GitHub Flow (simple, continuous delivery)
Best for teams that deploy frequently:
mainis always deployable- Create a feature branch for every change
- Open a pull request when ready for review
- Merge to
mainafter approval - Deploy immediately
git checkout -b feature/add-user-auth
# ... make changes ...
git push origin feature/add-user-auth
# Open PR → review → merge → deploy
Git Flow (structured releases)
Best for products with versioned releases (apps, libraries):
main— production code onlydevelop— integration branchfeature/*— new features (branch fromdevelop)release/*— release preparation (branch fromdevelop)hotfix/*— urgent production fixes (branch frommain)
More structured but adds overhead. Use GitHub Flow unless you have a genuine need for parallel release management.
Trunk-Based Development
Developers commit directly to main (or short-lived branches < 1 day). Feature flags control what users see. Requires strong CI/CD and test coverage. Used by Google, Facebook, and high-velocity teams.
Writing great commit messages
The commit message is a letter to your future self (and teammates). Follow the Conventional Commits format:
<type>(<scope>): <short summary>
<optional body — what and why, not how>
<optional footer — breaking changes, issue refs>
Types:
feat— new featurefix— bug fixdocs— documentation onlyrefactor— code change that neither fixes a bug nor adds a featuretest— adding or fixing testschore— build process, dependencies, tooling
Examples:
feat(auth): add JWT refresh token rotation
Implements sliding session windows using refresh token rotation.
Previous tokens are invalidated on use to detect theft.
Closes #142
fix(api): return 404 instead of 500 for missing user
The /users/:id endpoint was throwing an unhandled exception when
the user didn't exist. Now returns a proper 404 with error message.
Rule of thumb: If your commit message is
fix stufforWIP, your team hates you. Make it descriptive.
Merge vs. Rebase
Merge
git checkout main
git merge feature/my-feature
Creates a merge commit that joins two branches. Preserves full history — you can see exactly when branches diverged and merged.
A → B → C → M (merge commit)
↑ ↑
E → F (feature)
Use merge for: integrating long-running branches, preserving context in history.
Rebase
git checkout feature/my-feature
git rebase main
Replays your commits on top of the target branch. Creates a linear history — looks like the feature was built on top of the latest main.
Before: A → B → C (main)
↑
D → E (feature, based off B)
After: A → B → C → D' → E' (feature rebased onto C)
Use rebase for: cleaning up local commits before a PR, keeping feature branches up to date.
Golden rule: Never rebase commits that have been pushed to a shared branch. Rebase rewrites history — it breaks other people's local branches.
Interactive rebase: cleaning up history
Before opening a PR, squash and fixup messy work-in-progress commits:
git rebase -i HEAD~4 # interactively edit the last 4 commits
Options in the interactive editor:
pick— keep the commitsquash— merge into the previous commit, combine messagesfixup— merge into the previous commit, discard messagereword— keep changes, edit messagedrop— delete the commit entirely
Handling conflicts
Conflicts happen when two branches modify the same lines. Git marks them:
<<<<<<< HEAD (your branch)
const timeout = 5000;
=======
const timeout = 3000;
>>>>>>> feature/update-timeouts
Resolve by editing the file to the correct state (removing the markers), then:
git add src/config.ts
git merge --continue # or git rebase --continue
Prevention is better than cure:
- Pull from
mainfrequently to keep branches short-lived - Communicate with teammates when working on the same files
- Keep PRs small — large PRs have more conflicts and harder reviews
Essential daily commands
# Start a new feature
git checkout -b feature/my-feature
# Stage specific changes (not the whole file)
git add -p
# View unstaged changes
git diff
# View staged changes
git diff --staged
# Amend the last commit (before pushing)
git commit --amend --no-edit
# Temporarily save uncommitted work
git stash
git stash pop
# Find which commit introduced a bug (binary search)
git bisect start
git bisect bad # current commit is bad
git bisect good v1.2.0 # last known good commit
# Recover a deleted branch or lost commit
git reflog
# See a visual graph of branches
git log --oneline --graph --all
Pull request best practices
A good PR:
- Does one thing — reviewers can understand the full change
- Has a clear description — what changed, why, and how to test it
- Is small — < 400 lines of diff as a rough target
- Passes CI — never ask for review on a broken build
- Links to the issue —
Closes #42auto-closes the issue on merge
Use our README Generator to scaffold documentation alongside your code changes.
.gitignore essentials
Always add these to .gitignore:
# Environment variables
.env
.env.local
.env.*.local
# Dependencies
node_modules/
vendor/
# Build output
dist/
build/
.next/
# OS files
.DS_Store
Thumbs.db
# Editor files
.vscode/settings.json
.idea/
*.swp
Generate a project-specific .gitignore at gitignore.io — it knows about hundreds of languages and tools.
Git mastery compounds over time. Learn the mental model, adopt good commit habits, and your team's collaboration will become dramatically smoother.