Git Workflow Patterns
Best practices for Git version control, branching strategies, and collaborative development.
When to Activate
- Setting up Git workflow for a new project
- Deciding on branching strategy (GitFlow, trunk-based, GitHub flow)
- Writing commit messages and PR descriptions
- Resolving merge conflicts
- Managing releases and version tags
- Onboarding new team members to Git practices
Branching Strategies
GitHub Flow (Simple, Recommended for Most)
Best for continuous deployment and small-to-medium teams.
main (protected, always deployable)
│
├── feature/user-auth → PR → merge to main
├── feature/payment-flow → PR → merge to main
└── fix/login-bug → PR → merge to main
Rules:
mainis always deployable- Create feature branches from
main - Open Pull Request when ready for review
- After approval and CI passes, merge to
main - Deploy immediately after merge
Trunk-Based Development (High-Velocity Teams)
Best for teams with strong CI/CD and feature flags.
main (trunk)
│
├── short-lived feature (1-2 days max)
├── short-lived feature
└── short-lived feature
Rules:
- Everyone commits to
mainor very short-lived branches - Feature flags hide incomplete work
- CI must pass before merge
- Deploy multiple times per day
GitFlow (Complex, Release-Cycle Driven)
Best for scheduled releases and enterprise projects.
main (production releases)
│
└── develop (integration branch)
│
├── feature/user-auth
├── feature/payment
│
├── release/1.0.0 → merge to main and develop
│
└── hotfix/critical → merge to main and develop
Rules:
maincontains production-ready code onlydevelopis the integration branch- Feature branches from
develop, merge back todevelop - Release branches from
develop, merge tomainanddevelop - Hotfix branches from
main, merge to bothmainanddevelop
When to Use Which
| Strategy | Team Size | Release Cadence | Best For | |----------|-----------|-----------------|----------| | GitHub Flow | Any | Continuous | SaaS, web apps, startups | | Trunk-Based | 5+ experienced | Multiple/day | High-velocity teams, feature flags | | GitFlow | 10+ | Scheduled | Enterprise, regulated industries |
Commit Messages
Conventional Commits Format
<type>(<scope>): <subject>[optional body]
[optional footer(s)]
Types
| Type | Use For | Example |
|------|---------|---------|
| feat | New feature | feat(auth): add OAuth2 login |
| fix | Bug fix | fix(api): handle null response in user endpoint |
| docs | Documentation | docs(readme): update installation instructions |
| style | Formatting, no code change | style: fix indentation in login component |
| refactor | Code refactoring | refactor(db): extract connection pool to module |
| test | Adding/updating tests | test(auth): add unit tests for token validation |
| chore | Maintenance tasks | chore(deps): update dependencies |
| perf | Performance improvement | perf(query): add index to users table |
| ci | CI/CD changes | ci: add PostgreSQL service to test workflow |
| revert | Revert previous commit | revert: revert "feat(auth): add OAuth2 login" |
Good vs Bad Examples
# BAD: Vague, no context
git commit -m "fixed stuff"
git commit -m "updates"
git commit -m "WIP"GOOD: Clear, specific, explains why
git commit -m "fix(api): retry requests on 503 Service UnavailableThe external API occasionally returns 503 errors during peak hours.
Added exponential backoff retry logic with max 3 attempts.
Closes #123"
Commit Message Template
Create .gitmessage in repo root:
# <type>(<scope>): <subject>
# Types: feat, fix, docs, style, refactor, test, chore, perf, ci, revert
Scope: api, ui, db, auth, etc.
Subject: imperative mood, no period, max 50 chars
#
[optional body] - explain why, not what
[optional footer] - Breaking changes, closes #issue
Enable with: git config commit.template .gitmessage
Merge vs Rebase
Merge (Preserves History)
# Creates a merge commit
git checkout main
git merge feature/user-authResult:
* merge commit
|\
| * feature commits
|/
* main commits
Use when:
- Merging feature branches into
main - You want to preserve exact history
- Multiple people worked on the branch
- The branch has been pushed and others may have based work on it
Rebase (Linear History)
# Rewrites feature commits onto target branch
git checkout feature/user-auth
git rebase mainResult:
* feature commits (rewritten)
* main commits
Use when:
- Updating your local feature branch with latest
main - You want a linear, clean history
- The branch is local-only (not pushed)
- You're the only one working on the branch
Rebase Workflow
# Update feature branch with latest main (before PR)
git checkout feature/user-auth
git fetch origin
git rebase origin/mainFix any conflicts
Tests should still pass
Force push (only if you're the only contributor)
git push --force-with-lease origin feature/user-auth
When NOT to Rebase
# NEVER rebase branches that:
- Have been pushed to a shared repository
- Other people have based work on
- Are protected branches (main, develop)
- Are already merged
Why: Rebase rewrites history, breaking others' work
Pull Request Workflow
PR Title Format
<type>(<scope>): <description>Examples:
feat(auth): add SSO support for enterprise users
fix(api): resolve race condition in order processing
docs(api): add OpenAPI specification for v2 endpoints
PR Description Template
## WhatBrief description of what this PR does.
Why
Explain the motivation and context.
How
Key implementation details worth highlighting.
Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manual testing performed
Screenshots (if applicable)
Before/after screenshots for UI changes.
Checklist
- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex logic
- [ ] Documentation updated
- [ ] No new warnings introduced
- [ ] Tests pass locally
- [ ] Related issues linked
Closes #123
Code Review Checklist
For Reviewers:
- [ ] Does the code solve the stated problem?
- [ ] Are there any edge cases not handled?
- [ ] Is the code readable and maintainable?
- [ ] Are there sufficient tests?
- [ ] Are there security concerns?
- [ ] Is the commit history clean (squashed if needed)?
- [ ] Self-review completed before requesting review
- [ ] CI passes (tests, lint, typecheck)
- [ ] PR size is reasonable (<500 lines ideal)
- [ ] Related to a single feature/fix
- [ ] Description clearly explains the change
Conflict Resolution
Identify Conflicts
# Check for conflicts before merge
git checkout main
git merge feature/user-auth --no-commit --no-ffIf conflicts, Git will show:
CONFLICT (content): Merge conflict in src/auth/login.ts
Automatic merge failed; fix conflicts and then commit the result.
Resolve Conflicts
# See conflicted files
git statusView conflict markers in file
<<<<<<< HEAD
content from main
=======
content from feature branch
>>>>>>> feature/user-auth
Option 1: Manual resolution
Edit file, remove markers, keep correct content
Option 2: Use merge tool
git mergetoolOption 3: Accept one side
git checkout --ours src/auth/login.ts # Keep main version
git checkout --theirs src/auth/login.ts # Keep feature versionAfter resolving, stage and commit
git add src/auth/login.ts
git commit
Conflict Prevention Strategies
# 1. Keep feature branches small and short-lived
2. Rebase frequently onto main
git checkout feature/user-auth
git fetch origin
git rebase origin/main3. Communicate with team about touching shared files
4. Use feature flags instead of long-lived branches
5. Review and merge PRs promptly
Branch Management
Naming Conventions
# Feature branches
feature/user-authentication
feature/JIRA-123-payment-integrationBug fixes
fix/login-redirect-loop
fix/456-null-pointer-exceptionHotfixes (production issues)
hotfix/critical-security-patch
hotfix/database-connection-leakReleases
release/1.2.0
release/2024-01-hotfixExperiments/POCs
experiment/new-caching-strategy
poc/graphql-migration
Branch Cleanup
# Delete local branches that are merged
git branch --merged main | grep -v "^\*\|main" | xargs -n 1 git branch -dDelete remote-tracking references for deleted remote branches
git fetch -pDelete local branch
git branch -d feature/user-auth # Safe delete (only if merged)
git branch -D feature/user-auth # Force deleteDelete remote branch
git push origin --delete feature/user-auth
Stash Workflow
# Save work in progress
git stash push -m "WIP: user authentication"List stashes
git stash listApply most recent stash
git stash popApply specific stash
git stash apply stash@{2}Drop stash
git stash drop stash@{0}
Release Management
Semantic Versioning
MAJOR.MINOR.PATCHMAJOR: Breaking changes
MINOR: New features, backward compatible
PATCH: Bug fixes, backward compatible
Examples:
1.0.0 → 1.0.1 (patch: bug fix)
1.0.1 → 1.1.0 (minor: new feature)
1.1.0 → 2.0.0 (major: breaking change)
Creating Releases
# Create annotated tag
git tag -a v1.2.0 -m "Release v1.2.0Features:
- Add user authentication
- Implement password reset
Fixes:
- Resolve login redirect issue
Breaking Changes:
- None"
Push tag to remote
git push origin v1.2.0List tags
git tag -lDelete tag
git tag -d v1.2.0
git push origin --delete v1.2.0
Changelog Generation
# Generate changelog from commits
git log v1.1.0..v1.2.0 --oneline --no-mergesOr use conventional-changelog
npx conventional-changelog -i CHANGELOG.md -s
Git Configuration
Essential Configs
# User identity
git config --global user.name "Your Name"
git config --global user.email "[email protected]"Default branch name
git config --global init.defaultBranch mainPull behavior (rebase instead of merge)
git config --global pull.rebase truePush behavior (push current branch only)
git config --global push.default currentAuto-correct typos
git config --global help.autocorrect 1Better diff algorithm
git config --global diff.algorithm histogramColor output
git config --global color.ui auto
Useful Aliases
# Add to ~/.gitconfig
[alias]
co = checkout
br = branch
ci = commit
st = status
unstage = reset HEAD --
last = log -1 HEAD
visual = log --oneline --graph --all
amend = commit --amend --no-edit
wip = commit -m "WIP"
undo = reset --soft HEAD~1
contributors = shortlog -sn
Gitignore Patterns
# Dependencies
node_modules/
vendor/Build outputs
dist/
build/
*.o
*.exeEnvironment files
.env
.env.local
.env.*.localIDE
.idea/
.vscode/
*.swp
*.swoOS files
.DS_Store
Thumbs.dbLogs
*.log
logs/Test coverage
coverage/Cache
.cache/
*.tsbuildinfo
Common Workflows
Starting a New Feature
# 1. Update main branch
git checkout main
git pull origin main2. Create feature branch
git checkout -b feature/user-auth3. Make changes and commit
git add .
git commit -m "feat(auth): implement OAuth2 login"4. Push to remote
git push -u origin feature/user-auth5. Create Pull Request on GitHub/GitLab
Updating a PR with New Changes
# 1. Make additional changes
git add .
git commit -m "feat(auth): add error handling"2. Push updates
git push origin feature/user-auth
Syncing Fork with Upstream
# 1. Add upstream remote (once)
git remote add upstream https://github.com/original/repo.git2. Fetch upstream
git fetch upstream3. Merge upstream/main into your main
git checkout main
git merge upstream/main4. Push to your fork
git push origin main
Undoing Mistakes
# Undo last commit (keep changes)
git reset --soft HEAD~1Undo last commit (discard changes)
git reset --hard HEAD~1Undo last commit pushed to remote
git revert HEAD
git push origin mainUndo specific file changes
git checkout HEAD -- path/to/fileFix last commit message
git commit --amend -m "New message"Add forgotten file to last commit
git add forgotten-file
git commit --amend --no-edit
Git Hooks
Pre-Commit Hook
#!/bin/bash
.git/hooks/pre-commit
Run linting
npm run lint || exit 1Run tests
npm test || exit 1Check for secrets
if git diff --cached | grep -E '(password|api_key|secret)'; then
echo "Possible secret detected. Commit aborted."
exit 1
fi
Pre-Push Hook
#!/bin/bash
.git/hooks/pre-push
Run full test suite
npm run test:all || exit 1Check for console.log statements
if git diff origin/main | grep -E 'console\.log'; then
echo "Remove console.log statements before pushing."
exit 1
fi
Anti-Patterns
# BAD: Committing directly to main
git checkout main
git commit -m "fix bug"GOOD: Use feature branches and PRs
BAD: Committing secrets
git add .env # Contains API keysGOOD: Add to .gitignore, use environment variables
BAD: Giant PRs (1000+ lines)
GOOD: Break into smaller, focused PRs
BAD: "Update" commit messages
git commit -m "update"
git commit -m "fix"GOOD: Descriptive messages
git commit -m "fix(auth): resolve redirect loop after login"BAD: Rewriting public history
git push --force origin mainGOOD: Use revert for public branches
git revert HEADBAD: Long-lived feature branches (weeks/months)
GOOD: Keep branches short (days), rebase frequently
BAD: Committing generated files
git add dist/
git add node_modules/GOOD: Add to .gitignore
Quick Reference
| Task | Command |
|------|---------|
| Create branch | git checkout -b feature/name |
| Switch branch | git checkout branch-name |
| Delete branch | git branch -d branch-name |
| Merge branch | git merge branch-name |
| Rebase branch | git rebase main |
| View history | git log --oneline --graph |
| View changes | git diff |
| Stage changes | git add . or git add -p |
| Commit | git commit -m "message" |
| Push | git push origin branch-name |
| Pull | git pull origin branch-name |
| Stash | git stash push -m "message" |
| Undo last commit | git reset --soft HEAD~1 |
| Revert commit | git revert HEAD |