Following established best practices helps teams work more efficiently and maintain high-quality codebases. This guide covers essential conventions and strategies for professional Git usage.
Commit Best Practices
Make Atomic Commits
Each commit should represent a single logical change:
One purpose per commit
A commit should do one thing and do it completely. If you’re using “and” in your commit message, you might need multiple commits.# Good: Separate commits
git commit -m "Add user authentication endpoint"
git commit -m "Add tests for authentication"
git commit -m "Update API documentation"
# Bad: Combined commit
git commit -m "Add authentication, tests, and docs"
Complete and working
Each commit should leave the codebase in a working state. It should compile and pass existing tests.# Test before committing
npm test
git commit -m "Fix pagination bug in user list"
Self-contained
The commit should include all necessary changes. Don’t split related changes across multiple commits.# Include both the code and corresponding test
git add src/validator.js tests/validator.test.js
git commit -m "Add email validation function"
Write Clear Commit Messages
Good commit messages are essential for collaboration and maintenance:
Format:
Subject line (50 chars or less)
Body explaining what and why (wrap at 72 chars)
Fixes: #123
Subject line guidelines:
- Use imperative mood: “Fix bug” not “Fixed bug” or “Fixes bug”
- Capitalize the first word
- No period at the end
- Be specific: “Fix null pointer in user service” not “Fix bug”
Examples:
# Good commit messages
git commit -m "Add password strength validation"
git commit -m "Fix race condition in payment processing
The payment processor was not properly handling concurrent requests,
which could result in duplicate charges. This adds proper locking
to ensure requests are processed sequentially.
Fixes: #456"
git commit -m "Refactor authentication module for testability
Split the monolithic auth service into smaller, focused functions.
This makes it easier to test individual components and reduces
coupling with the database layer.
Breaking change: Auth middleware signature has changed.
See migration guide for details."
# Poor commit messages (avoid these)
git commit -m "fix" # Too vague
git commit -m "Fixed the bug where users couldn't login sometimes" # Past tense
git commit -m "Updated files" # Not descriptive
git commit -m "WIP" # Should not be pushed
Many teams use conventional commits format:
feat: for new features
fix: for bug fixes
docs: for documentation
refactor: for refactoring
test: for tests
chore: for maintenance
Example: feat: add OAuth2 authentication
When to Commit
Commit frequency matters:
# Commit after completing logical units
# Too frequent:
git commit -m "Add function name" # Incomplete
git commit -m "Add function body" # Should be one commit
# Good frequency:
git commit -m "Add user validation function" # Complete unit
git commit -m "Add tests for user validation" # Another logical unit
# Too infrequent:
git commit -m "Implement entire user management system" # Too much
Branch Management
Naming Conventions
Use descriptive, consistent branch names:
Common patterns:
feature/user-authentication
bugfix/fix-login-redirect
hotfix/security-patch-1.2.3
release/v2.0.0
refactor/simplify-api-client
Guidelines:
- Use lowercase with hyphens
- Include category prefix (feature, bugfix, etc.)
- Be descriptive but concise
- Include ticket number if applicable:
feature/PROJ-123-add-search
# Good branch names
git switch -c feature/oauth-integration
git switch -c bugfix/fix-memory-leak
git switch -c hotfix/critical-security-fix
# Poor branch names
git switch -c new-feature # Not descriptive
git switch -c johns-branch # Based on person, not purpose
git switch -c fix # Too vague
Branch Lifecycle
Create from main
git switch main
git pull origin main
git switch -c feature/new-feature
Develop and commit
# Make incremental commits
git commit -m "Add API endpoint"
git commit -m "Add endpoint tests"
git commit -m "Update documentation"
Keep updated
# Periodically sync with main
git fetch origin
git rebase origin/main # Or merge, depending on team policy
Clean up before merging
# Squash fixup commits, reorder, edit messages
git rebase -i origin/main
Merge and delete
git switch main
git merge --no-ff feature/new-feature
git push origin main
git branch -d feature/new-feature
git push origin --delete feature/new-feature
Branch Protection
Protect important branches:
- Require pull request reviews
- Require status checks to pass
- Require branches to be up to date
- Restrict who can push
- Require signed commits
- Prevent force pushes
Code Review Practices
For Authors
Before requesting review:
# Self-review your changes
git diff main...your-branch
# Check for:
# - Debug code or console.logs
# - Commented-out code
# - TODO comments
# - Unnecessary whitespace changes
# - Large files accidentally committed
# Clean up commit history
git rebase -i main
# Ensure tests pass
npm test
# Run linters
npm run lint
Pull request guidelines:
## Description
Clear explanation of what and why
## Changes
- Focused list of changes
- Keep PR scope reasonable (< 400 lines when possible)
## Testing
- How was this tested?
- What edge cases were considered?
## Checklist
- [ ] Tests added/updated
- [ ] Documentation updated
- [ ] No breaking changes (or documented)
- [ ] Follows coding standards
Responding to feedback:
# Address feedback in new commits
git commit -m "Address review feedback: improve error handling"
# Or fixup commits if you'll squash
git commit --fixup=<original-commit-hash>
# After approval, clean up
git rebase -i --autosquash main
For Reviewers
What to look for:
- Correctness: Does it work? Does it handle edge cases?
- Design: Is it well-architected?
- Complexity: Is it unnecessarily complex?
- Tests: Are there tests? Do they test the right things?
- Naming: Are names clear and consistent?
- Documentation: Are comments helpful? Is documentation updated?
- Style: Does it follow team conventions?
How to provide feedback:
# Be specific and constructive
❌ "This is wrong"
✅ "This could cause a race condition when multiple users access simultaneously. Consider adding a mutex."
# Distinguish between critical and optional
❌ "Fix this"
✅ "Critical: This will cause a security vulnerability"
✅ "Nit: Consider renaming for clarity"
✅ "Suggestion: Could be simplified using..."
# Acknowledge good work
✅ "Nice refactoring! Much cleaner than before."
✅ "Good catch on this edge case."
Repository Organization
File Structure
# Keep repository root clean
project/
├── .git/
├── .gitignore
├── .gitattributes
├── README.md
├── CONTRIBUTING.md
├── LICENSE
├── src/
├── tests/
├── docs/
└── scripts/
README Best Practices
Every repository should have a comprehensive README:
# Project Name
Brief description of what the project does
## Features
- Key feature 1
- Key feature 2
## Installation
```bash
npm install
Usage
Development
Contributing
See CONTRIBUTING.md
License
MIT - See LICENSE
### .gitignore Strategy
Maintain a comprehensive .gitignore:
```bash
# Operating System
.DS_Store
Thumbs.db
# IDEs
.vscode/
.idea/
*.swp
*.swo
# Dependencies
node_modules/
vendor/
# Build output
dist/
build/
*.log
# Environment files
.env
.env.local
*.pem
# Temporary files
tmp/
*.tmp
Use gitignore.io to generate .gitignore templates for your tech stack.
History Management
Keep History Clean
Use rebase for local cleanup:
# Before pushing, clean up commit history
git rebase -i origin/main
# Squash fixup commits
git commit --fixup=<hash>
git rebase -i --autosquash main
Avoid force pushing to shared branches:
# Safe force push (checks remote hasn't changed)
git push --force-with-lease origin feature-branch
# Never do this on main/shared branches
git push --force origin main # ❌ Dangerous!
When to Squash
Squash these commits:
- “Fix typo”
- “WIP”
- “Address review comments”
- Multiple commits for one logical change
Keep these commits separate:
- Different logical changes
- Changes to different subsystems
- Commits that aid bisecting
- Commits with different authors
# Interactive rebase to squash
git rebase -i HEAD~5
# In the editor:
pick abc123 Add feature
fixup def456 Fix typo in feature
fixup ghi789 Another typo fix
pick jkl012 Add tests for feature
pick mno345 Update documentation
Security Best Practices
Never Commit Secrets
Prevention:
# Use environment variables
DATABASE_URL=postgres://localhost/db # In .env
# Add to .gitignore
echo ".env" >> .gitignore
echo "*.pem" >> .gitignore
echo "config/secrets.yml" >> .gitignore
# Use git-secrets or similar tools
git secrets --install
git secrets --register-aws
Use placeholder files:
# Commit .env.example, not .env
# .env.example:
DATABASE_URL=postgres://localhost/mydb
API_KEY=your-api-key-here
SECRET_KEY=generate-random-secret
# Users copy and customize
cp .env.example .env
Signed Commits
Sign commits to verify your identity:
# Configure GPG key
git config --global user.signingkey <key-id>
git config --global commit.gpgSign true
# Sign a commit
git commit -S -m "Signed commit"
# Verify signatures
git log --show-signature
Repository Size
Keep repositories focused:
- Don’t commit build artifacts
- Don’t commit dependencies (use package managers)
- Don’t commit large binary files (use Git LFS)
- Don’t commit generated files
Use Git LFS for large files:
# Install Git LFS
git lfs install
# Track large files
git lfs track "*.psd"
git lfs track "*.mp4"
# Commit .gitattributes
git add .gitattributes
git commit -m "Configure Git LFS"
Optimize Operations
# Regular maintenance
git gc --aggressive
git prune
# Shallow clone for CI/CD
git clone --depth 1 <url>
# Sparse checkout for large repos
git sparse-checkout init --cone
git sparse-checkout set src/component
Team Conventions
Establish Workflow Guidelines
Document your team’s conventions:
CONTRIBUTING.md example:
# Contributing Guidelines
## Workflow
1. Create a feature branch from `main`
2. Make changes in small, atomic commits
3. Push and create a pull request
4. Address review feedback
5. Squash commits before merging
## Commit Messages
Use conventional commits format:
- feat: New features
- fix: Bug fixes
- docs: Documentation only
- refactor: Code refactoring
## Code Review
- All PRs require at least one approval
- Address all comments before merging
- Keep PRs focused and under 400 lines
## Testing
- All changes must include tests
- All tests must pass before merging
- Maintain >80% code coverage
Automation
Use Git hooks to enforce standards:
# .git/hooks/pre-commit
#!/bin/bash
# Run linter
npm run lint || exit 1
# Run tests
npm test || exit 1
# Check for secrets
git secrets --scan || exit 1
echo "Pre-commit checks passed"
Common Anti-Patterns to Avoid
- Committing directly to main: Always use feature branches
- Huge commits: Break down into smaller, logical commits
- Unclear commit messages: Write descriptive messages
- Not pulling before pushing: Stay synchronized
- Force pushing to shared branches: Coordinate with team
- Committing generated files: Use .gitignore
- Long-lived feature branches: Merge or rebase frequently
- Not testing before committing: Test locally first
- Mixing formatting and logic changes: Separate concerns
- Not documenting breaking changes: Update documentation and changelog
These best practices are guidelines, not absolute rules. Adapt them to your team’s needs and project requirements. The key is consistency within your team.