Git Workflow & Best Practices for Development Teams
Effective Git workflows are the backbone of successful team collaboration. Poor Git practices lead to merge conflicts, lost work, and wasted time. Let's explore proven strategies that professional teams use every day.
Why Git Workflow Matters
A solid Git strategy provides:
- Clear History - Understand what changed and why
- Safe Collaboration - Multiple developers working simultaneously
- Easy Rollbacks - Revert problematic changes quickly
- Code Quality - Review before merging to main
- CI/CD Integration - Automated testing and deployment
Popular Branching Strategies
Git Flow (Traditional)
Best for projects with scheduled releases:
# Main branches
main # Production-ready code
develop # Integration branch
# Supporting branches
feature/* # New features
release/* # Release preparation
hotfix/* # Production fixes
Workflow:
# Start class="keyword">new feature
git checkout develop
git checkout -b feature/user-authentication
# Work on feature
git add .
git commit -m class="keyword">class="string">"feat: implement JWT authentication"
# Merge back to develop
git checkout develop
git merge feature/user-authentication
GitHub Flow (Simplified)
Perfect for continuous deployment:
main # Always deployable
feature/* # All changes are features
Benefits:
- Simpler than Git Flow
- Faster deployments
- Better for web applications
Trunk-Based Development
Used by high-performing teams:
class="keyword">class="comment">// Short-lived branches(1-2 days max)
main; class="keyword">class="comment">// Always stable
feature / quick - fix; class="keyword">class="comment">// Small, focused changes
class="keyword">class="comment">// Feature flags class="keyword">class="keyword">for incomplete features
class="keyword">class="keyword">const features = {
newDashboard: process.env.FEATURE_NEW_DASHBOARD === class="keyword">class="string">"true",
aiAssistant: process.env.FEATURE_AI_ASSISTANT === class="keyword">class="string">"true",
};
Commit Message Best Practices
Conventional Commits
Follow a standard format:
<class="keyword">type>():
Types:
- feat: New feature
- fix: Bug fix
- docs: Documentation changes
- style: Code formatting
- refactor: Code restructuring
- test: Adding tests
- chore: Maintenance tasks
Examples:
feat(auth): add OAuth2 login with Google
Implement Google OAuth2 authentication flow using NextAuth.js.
Users can now sign in with their Google accounts.
Closes #123
---
fix(api): resolve race condition in user creation
The user creation endpoint was vulnerable to race conditions
when multiple requests arrived simultaneously.
Fixes #456
---
docs(readme): update installation instructions
Add missing environment variables and clarify setup steps.
Essential Git Commands
Daily Workflow
# Update your local main
git checkout main
git pull origin main
# Create feature branch
git checkout -b feature/class="keyword">new-dashboard
# Stage and commit changes
git add src/components/Dashboard.tsx
git commit -m class="keyword">class="string">"feat(dashboard): add analytics widget"
# Push to remote
git push origin feature/class="keyword">new-dashboard
# Update branch with latest main
git checkout main
git pull origin main
git checkout feature/class="keyword">new-dashboard
git rebase main
Handling Conflicts
# During rebase or merge
git status # See conflicted files
# Manually resolve conflicts in editor
git add resolved-file.ts
git rebase --class="keyword">continue
# Abort class="keyword">class="keyword">if needed
git rebase --abort
Useful Commands
# View commit history
git log --oneline --graph --all
# Undo last commit(keep changes)
git reset --soft HEAD~1
# Discard local changes
git checkout -- file.ts
# Stash work in progress
git stash save class="keyword">class="string">"work in progress"
git stash pop
# Interactive rebase(clean up commits)
git rebase -i HEAD~3
Pull Request Best Practices
Creating Great PRs
class="keyword">class=class="keyword">class="string">"mt-8 mb-4 text-3xl font-bold text-zinc-900 dark:text-zinc-50">Description
Add user profile page with avatar upload functionality.
class="keyword">class=class="keyword">class="string">"mt-8 mb-4 text-3xl font-bold text-zinc-900 dark:text-zinc-50">Changes
- Created ProfilePage component
- Implemented image upload with S3
- Added profile edit form with validation
- Updated user API endpoints
class="keyword">class=class="keyword">class="string">"mt-8 mb-4 text-3xl font-bold text-zinc-900 dark:text-zinc-50">Testing
- ✅ Unit tests class="keyword">class="keyword">for ProfilePage
- ✅ API integration tests
- ✅ Manual testing on staging
class="keyword">class=class="keyword">class="string">"mt-8 mb-4 text-3xl font-bold text-zinc-900 dark:text-zinc-50">Screenshots
[Include relevant screenshots]
class="keyword">class=class="keyword">class="string">"mt-8 mb-4 text-3xl font-bold text-zinc-900 dark:text-zinc-50">Checklist
- [x] Code follows style guidelines
- [x] Tests added/updated
- [x] Documentation updated
- [x] No console.log or debugging code
Review Process
# Checkout PR locally class="keyword">class="keyword">for testing
gh pr checkout 123
# Run tests
npm test
# Leave feedback
gh pr review 123 --comment -b class="keyword">class="string">"LGTM! Great work on error handling."
.gitignore Best Practices
# Dependencies
node_modules/
.pnp/
# Environment variables
.env
.env.local
.env*.local
# Build outputs
dist/
build/
.next/
out/
# IDE
.vscode/
.idea/
*.swp
# OS
.DS_Store
Thumbs.db
# Logs
*.log
logs/
# Testing
coverage/
.nyc_output/
Protecting Your Main Branch
GitHub repository settings:
Branch Protection Rules: ✅ Require pull request reviews(2 approvals)
✅ Require status checks to pass
✅ Require branches to be up to date
✅ Require conversation resolution
✅ Include administrators
✅ Restrict force pushes
Git Hooks for Automation
Pre-commit Hook
#!/bin/bash
# .git/hooks/pre-commit
# Run linter
npm run lint || exit 1
# Run class="keyword">type check
npm run class="keyword">type-check || exit 1
# Run tests
npm test || exit 1
echo class="keyword">class="string">"✅ All checks passed!"
Using Husky
{
class="keyword">class="string">"husky": {
class="keyword">class="string">"hooks": {
class="keyword">class="string">"pre-commit": class="keyword">class="string">"lint-staged",
class="keyword">class="string">"commit-msg": class="keyword">class="string">"commitlint -E HUSKY_GIT_PARAMS"
}
},
class="keyword">class="string">"lint-staged": {
class="keyword">class="string">"*.{ts,tsx}": [class="keyword">class="string">"eslint --fix", class="keyword">class="string">"prettier --write"],
class="keyword">class="string">"*.{json,md}": [class="keyword">class="string">"prettier --write"]
}
}
Common Mistakes to Avoid
❌ Don't:
- Commit directly to main
- Write vague commit messages ("fixed stuff")
- Create massive PRs (500+ lines)
- Force push to shared branches
- Commit sensitive data (API keys, passwords)
- Leave console.log in production code
✅ Do:
- Use feature branches
- Write descriptive commit messages
- Keep PRs focused and small
- Communicate with your team
- Use .gitignore properly
- Review your own code before requesting review
Useful Git Aliases
Add to ~/.gitconfig:
[alias]
st = status
co = checkout
br = branch
ci = commit
unstage = reset HEAD --
last = log -1 HEAD
visual = log --oneline --graph --all --decorate
undo = reset --soft HEAD~1
Conclusion
A solid Git workflow is essential for team productivity. Start with a simple strategy like GitHub Flow, enforce it with branch protection rules, and iterate based on your team's needs. Remember: consistency is more important than complexity.
The best workflow is the one your team actually follows. Start simple, document your process, and improve continuously based on real experience.
Key Takeaways:
- Choose a branching strategy that fits your team
- Write meaningful commit messages
- Keep PRs small and focused
- Protect your main branch
- Automate quality checks with Git hooks
- Communicate through code reviews
Happy collaborating! 🚀