Git Best Practices
Git is a powerful tool, but its power comes with responsibility. Bad habits — vague commit messages, working directly on main, no .gitignore — create problems that multiply over time. Good habits keep a project clean, understandable, and a pleasure to maintain for everyone who touches it.
1. Commit Messages
Write Meaningful Commit Messages
Every commit message should clearly communicate what changed and why. Future developers (including a future self six months from now) should be able to understand each commit without opening the files.
| Bad Message | Good Message |
|---|---|
| fix | Fix null reference error when user has no profile photo |
| update | Update login form to validate email format on submit |
| wip | Add initial structure for payment gateway integration |
| changes | Remove deprecated API calls from user service |
Commit Message Format (The 7 Rules)
- Limit the subject line to 72 characters
- Use the imperative mood — "Add feature" not "Added feature"
- Capitalize the first word
- Do not end the subject line with a period
- Separate subject from body with a blank line
- Use the body to explain what and why, not how
- Reference related issue numbers at the bottom
Example of a Well-Structured Commit
Fix shopping cart total not updating on quantity change
Previously, the cart total was calculated only on page load.
When users changed item quantities without refreshing, the
displayed total remained incorrect.
Added an event listener on quantity input fields to
recalculate and update the total dynamically.
Fixes #127
2. Commit Often, But Meaningfully
Commits should be small and focused — each one doing one logical thing. This makes the history easy to read, makes git bisect effective, and makes reverting specific changes easy.
- Good: One commit to add a feature, one commit to add its tests, one commit to add its documentation
- Bad: One massive commit mixing feature code, bug fixes, style changes, and renamed files all together
3. Never Commit Directly to Main
The main branch should always be in a deployable state. All work should happen on feature or fix branches and go through a pull request before reaching main.
# Wrong approach
git switch main
# ... make changes ...
git commit -m "Add feature"
git push origin main
# Right approach
git switch -c feature/user-notifications
# ... make changes ...
git commit -m "Add user notification system"
git push origin feature/user-notifications
# Open pull request for review
4. Pull Before Pushing
Always pull the latest changes from the remote before pushing. This prevents rejection errors and reduces the chance of conflicts building up unnoticed.
git pull origin main
git push origin main
5. Use .gitignore Properly
Set up a .gitignore file at the very beginning of every project. Never commit:
- Secrets, credentials, or API keys (
.env,config.secret.js) - Dependencies (
node_modules/,vendor/) - Build output (
dist/,build/,*.class) - OS/editor files (
.DS_Store,.idea/,*.swp) - Log files (
*.log)
6. Use Branches for Everything
Create a new branch for every feature, bug fix, experiment, or even documentation update. Branch names should be descriptive:
feature/user-profile-settings
fix/cart-total-calculation
docs/update-api-reference
chore/update-dependencies
refactor/extract-auth-service
7. Keep Branches Short-Lived
Long-lived feature branches accumulate divergence from main and lead to painful merges. Keep branches focused on a single task and merge them back quickly — ideally within days, not weeks.
8. Review Before Committing
Before every commit, review what is about to be committed:
git diff --staged # See exactly what will be committed
git status # Confirm no accidental files are staged
9. Use Tags for Releases
Mark every production release with an annotated tag using semantic versioning:
git tag -a v1.2.0 -m "Release v1.2.0 — Add payment integration"
git push origin --tags
10. Write a Good README
Every project repository should have a README.md that explains:
- What the project does
- How to install and run it locally
- How to run tests
- How to contribute
- License information
11. Never Force Push to Shared Branches
git push --force on a shared branch overwrites remote history and destroys other people's work. Only force push on personal branches that no one else is using:
# NEVER do this on shared branches
git push --force origin main ← Dangerous!
# Safer alternative on shared branches — always use revert
git revert <bad-commit-hash>
git push origin main
12. Protect the Main Branch on GitHub
Enable branch protection rules on GitHub for the main branch:
- Go to Repository → Settings → Branches
- Click "Add rule" for
main - Enable: "Require a pull request before merging"
- Enable: "Require status checks to pass before merging" (run tests automatically)
- Enable: "Include administrators" (protects from accidental direct pushes)
13. Rebase Feature Branches Before Merging
Before merging a feature branch, rebase it onto the latest main to produce a clean, linear history:
git switch feature/user-profile
git rebase main
git switch main
git merge --no-ff feature/user-profile
14. Clean Up Merged Branches
After a branch is merged, delete it to keep the repository clean:
# Delete local branch
git branch -d feature/user-profile
# Delete remote branch
git push origin --delete feature/user-profile
15. Avoid Storing Large Binary Files
Git is optimized for text files (source code). Storing large binary files (images, videos, binaries) in a Git repository makes it slow and bloated over time. Use Git LFS (Large File Storage) for large binary assets.
Quick Reference Checklist
| Practice | Status |
|---|---|
| Set up .gitignore before first commit | Essential |
| Write meaningful commit messages | Essential |
| Use feature branches for all work | Essential |
| Never commit secrets or credentials | Critical |
| Pull before pushing | Essential |
| Protect the main branch on GitHub | Highly Recommended |
| Review staged changes before committing | Recommended |
| Tag all releases | Recommended |
| Delete merged branches | Good Practice |
| Write a good README | Good Practice |
Summary
Good Git practices are not just about using the right commands — they are about creating a shared history that the whole team can understand and work with confidently. Write clear commit messages, use branches for every change, protect the main branch, and never commit secrets. These habits transform Git from a source of confusion into a powerful, reliable foundation for every project.
