git-workflow
Git workflow patterns including branching strategies, commit conventions, merge vs rebase, conflict resolution, and collaborative development best practices for teams of all sizes.
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 mainRules:
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 featureRules:
- 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 developRules:
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 contextgit commit -m "fixed stuff"git commit -m "updates"git commit -m "WIP"
# GOOD: Clear, specific, explains whygit commit -m "fix(api): retry requests on 503 Service Unavailable
The 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 #issueEnable with: git config commit.template .gitmessage
Merge vs Rebase
Merge (Preserves History)
# Creates a merge commitgit checkout maingit merge feature/user-auth
# Result:# * merge commit# |\# | * feature commits# |/# * main commitsUse 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 branchgit checkout feature/user-authgit rebase main
# Result:# * feature commits (rewritten)# * main commitsUse 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-authgit fetch origingit rebase origin/main
# Fix any conflicts# Tests should still pass
# Force push (only if you're the only contributor)git push --force-with-lease origin feature/user-authWhen 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' workPull Request Workflow
PR Title Format
<type>(<scope>): <description>
Examples:feat(auth): add SSO support for enterprise usersfix(api): resolve race condition in order processingdocs(api): add OpenAPI specification for v2 endpointsPR Description Template
## What
Brief 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 #123Code 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)?
For Authors:
- 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 mergegit checkout maingit merge feature/user-auth --no-commit --no-ff
# If 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 filesgit status
# View 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 toolgit mergetool
# Option 3: Accept one sidegit checkout --ours src/auth/login.ts # Keep main versiongit checkout --theirs src/auth/login.ts # Keep feature version
# After resolving, stage and commitgit add src/auth/login.tsgit commitConflict Prevention Strategies
# 1. Keep feature branches small and short-lived# 2. Rebase frequently onto maingit checkout feature/user-authgit fetch origingit rebase origin/main
# 3. Communicate with team about touching shared files# 4. Use feature flags instead of long-lived branches# 5. Review and merge PRs promptlyBranch Management
Naming Conventions
# Feature branchesfeature/user-authenticationfeature/JIRA-123-payment-integration
# Bug fixesfix/login-redirect-loopfix/456-null-pointer-exception
# Hotfixes (production issues)hotfix/critical-security-patchhotfix/database-connection-leak
# Releasesrelease/1.2.0release/2024-01-hotfix
# Experiments/POCsexperiment/new-caching-strategypoc/graphql-migrationBranch Cleanup
# Delete local branches that are mergedgit branch --merged main | grep -v "^\*\|main" | xargs -n 1 git branch -d
# Delete remote-tracking references for deleted remote branchesgit fetch -p
# Delete local branchgit branch -d feature/user-auth # Safe delete (only if merged)git branch -D feature/user-auth # Force delete
# Delete remote branchgit push origin --delete feature/user-authStash Workflow
# Save work in progressgit stash push -m "WIP: user authentication"
# List stashesgit stash list
# Apply most recent stashgit stash pop
# Apply specific stashgit stash apply stash@{2}
# Drop stashgit stash drop stash@{0}Release Management
Semantic Versioning
MAJOR.MINOR.PATCH
MAJOR: Breaking changesMINOR: New features, backward compatiblePATCH: 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 taggit tag -a v1.2.0 -m "Release v1.2.0
Features:- Add user authentication- Implement password reset
Fixes:- Resolve login redirect issue
Breaking Changes:- None"
# Push tag to remotegit push origin v1.2.0
# List tagsgit tag -l
# Delete taggit tag -d v1.2.0git push origin --delete v1.2.0Changelog Generation
# Generate changelog from commitsgit log v1.1.0..v1.2.0 --oneline --no-merges
# Or use conventional-changelognpx conventional-changelog -i CHANGELOG.md -sGit Configuration
Essential Configs
# User identitygit config --global user.name "Your Name"git config --global user.email "your@email.com"
# Default branch namegit config --global init.defaultBranch main
# Pull behavior (rebase instead of merge)git config --global pull.rebase true
# Push behavior (push current branch only)git config --global push.default current
# Auto-correct typosgit config --global help.autocorrect 1
# Better diff algorithmgit config --global diff.algorithm histogram
# Color outputgit config --global color.ui autoUseful 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 -snGitignore Patterns
# Dependenciesnode_modules/vendor/
# Build outputsdist/build/*.o*.exe
# Environment files.env.env.local.env.*.local
# IDE.idea/.vscode/*.swp*.swo
# OS files.DS_StoreThumbs.db
# Logs*.loglogs/
# Test coveragecoverage/
# Cache.cache/*.tsbuildinfoCommon Workflows
Starting a New Feature
# 1. Update main branchgit checkout maingit pull origin main
# 2. Create feature branchgit checkout -b feature/user-auth
# 3. Make changes and commitgit add .git commit -m "feat(auth): implement OAuth2 login"
# 4. Push to remotegit push -u origin feature/user-auth
# 5. Create Pull Request on GitHub/GitLabUpdating a PR with New Changes
# 1. Make additional changesgit add .git commit -m "feat(auth): add error handling"
# 2. Push updatesgit push origin feature/user-authSyncing Fork with Upstream
# 1. Add upstream remote (once)git remote add upstream https://github.com/original/repo.git
# 2. Fetch upstreamgit fetch upstream
# 3. Merge upstream/main into your maingit checkout maingit merge upstream/main
# 4. Push to your forkgit push origin mainUndoing Mistakes
# Undo last commit (keep changes)git reset --soft HEAD~1
# Undo last commit (discard changes)git reset --hard HEAD~1
# Undo last commit pushed to remotegit revert HEADgit push origin main
# Undo specific file changesgit checkout HEAD -- path/to/file
# Fix last commit messagegit commit --amend -m "New message"
# Add forgotten file to last commitgit add forgotten-filegit commit --amend --no-editGit Hooks
Pre-Commit Hook
#!/bin/bash# Run lintingnpm run lint || exit 1
# Run testsnpm test || exit 1
# Check for secretsif git diff --cached | grep -E '(password|api_key|secret)'; then echo "Possible secret detected. Commit aborted." exit 1fiPre-Push Hook
#!/bin/bash# Run full test suitenpm run test:all || exit 1
# Check for console.log statementsif git diff origin/main | grep -E 'console\.log'; then echo "Remove console.log statements before pushing." exit 1fiAnti-Patterns
# BAD: Committing directly to maingit checkout maingit commit -m "fix bug"
# GOOD: Use feature branches and PRs
# BAD: Committing secretsgit add .env # Contains API keys
# GOOD: Add to .gitignore, use environment variables
# BAD: Giant PRs (1000+ lines)# GOOD: Break into smaller, focused PRs
# BAD: "Update" commit messagesgit commit -m "update"git commit -m "fix"
# GOOD: Descriptive messagesgit commit -m "fix(auth): resolve redirect loop after login"
# BAD: Rewriting public historygit push --force origin main
# GOOD: Use revert for public branchesgit revert HEAD
# BAD: Long-lived feature branches (weeks/months)# GOOD: Keep branches short (days), rebase frequently
# BAD: Committing generated filesgit add dist/git add node_modules/
# GOOD: Add to .gitignoreQuick 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 |