Table of Contents Introduction Why clean commit history matters—even for side projects The Problem with Messy Commits– “Fix bug” and “test” everywhere– Hard to track what actually changed– Painful future debugging Adopting a Clean Commit Strategy– Write commits like you’ll read them in 6 months– Commit only what matters– Group related changes together Using Git Effectively During Development– git add -p for selective staging– git commit --amend to fix your last message– git rebase -i to clean up before pushing Avoiding Commit Spam– Why “commit often” doesn’t mean “commit everything”– Avoid noise like formatting, log removals, etc. Best Practices for Side Projects– Use feature branches—even when working solo– Keep your main branch deploy-ready– Write meaningful commit messages. Sample Commit Message Templates– Practical examples you can copy– How to use prefix conventions (e.g. feat:, fix:, chore:) Conclusion Keeping history clean so your future self doesn’t suffer Introduction Why clean commit history matters—even for side projects Introduction The Problem with Messy Commits– “Fix bug” and “test” everywhere– Hard to track what actually changed– Painful future debugging The Problem with Messy Commits Adopting a Clean Commit Strategy– Write commits like you’ll read them in 6 months– Commit only what matters– Group related changes together Adopting a Clean Commit Strategy Using Git Effectively During Development– git add -p for selective staging– git commit --amend to fix your last message– git rebase -i to clean up before pushing Using Git Effectively During Development git add -p git commit --amend git rebase -i Avoiding Commit Spam– Why “commit often” doesn’t mean “commit everything”– Avoid noise like formatting, log removals, etc. Avoiding Commit Spam Best Practices for Side Projects– Use feature branches—even when working solo– Keep your main branch deploy-ready– Write meaningful commit messages. Best Practices for Side Projects Sample Commit Message Templates– Practical examples you can copy– How to use prefix conventions (e.g. feat:, fix:, chore:) Sample Commit Message Templates feat: fix: chore: Conclusion Keeping history clean so your future self doesn’t suffer Conclusion Introduction Why clean commit history matters—even for side projects Why clean commit history matters—even for side projects It’s easy to treat side projects like a sandbox. No rules. No PR reviews. No pressure. Just code, commit, ship. And that’s fine—until you come back a month later and wonder: “What does fix-stuff-final3 even mean?” “What does fix-stuff-final3 even mean?” fix-stuff-final3 We’ve all done it. Messy commit histories feel harmless in the moment. But they quickly become a problem when: You need to debug a regression You want to roll back a change You’re trying to extract reusable code Or you’re prepping the repo for open source or job applications You need to debug a regression You want to roll back a change You’re trying to extract reusable code Or you’re prepping the repo for open source or job applications Clean commits aren’t just for large teams or open-source contributors. They help you, the solo developer, keep control over your own project. you A Messy History Slows You Down Here’s a real commit log from an old side project: commit 1a3f… fixed nav bug commit 23cd… fixed it again commit 91f0… test commit 3fa1… oops commit b7d2… backup before trying something commit 1a3f… fixed nav bug commit 23cd… fixed it again commit 91f0… test commit 3fa1… oops commit b7d2… backup before trying something At the time, it worked. But now? It’s unreadable. Unusable. Untrustworthy. Try running git bisect to track down a bug, and you’ll lose hours stepping through vague changes. git bisect A Clean History = A Clear Story Now compare that to a cleaned-up commit log: commit a34f… feat: add responsive mobile nav commit b28d… fix: handle logout button positioning bug commit 9d1c… refactor: extract NavBar component logic commit f4a1… chore: update README and screenshots commit a34f… feat: add responsive mobile nav commit b28d… fix: handle logout button positioning bug commit 9d1c… refactor: extract NavBar component logic commit f4a1… chore: update README and screenshots Each commit: Describes what changed Has a clear purpose Is scoped to a single idea Describes what changed Has a clear purpose Is scoped to a single idea This isn’t about perfection. It’s about thinking clearly and working with intention—even when no one else is watching. thinking clearly and working with intention Side Projects Grow Too That weekend prototype? It might turn into a paid product. Or a code sample you send in a job application. Or the base of your next freelance contract. When that happens, a clear commit history becomes your superpower: You can isolate features Roll back mistakes Understand old logic And hand it off to others, if needed You can isolate features Roll back mistakes Understand old logic And hand it off to others, if needed Example: Before vs After Cleaning Up Commits Let’s say you build a feature in a rush and commit like this: git commit -m "trying dark mode" git commit -m "ok fixed theme bug" git commit -m "final version" git commit -m "trying dark mode" git commit -m "ok fixed theme bug" git commit -m "final version" Instead, you can squash and rewrite them into something like: git commit -m "feat: add dark mode support with toggle button" git commit -m "feat: add dark mode support with toggle button" It’s now one meaningful unit. You know what it does. You know when it was added. And it’s easier to revert or improve in the future. The Problem with Messy Commits Why “fix bug” and “test” are slowing your team down Why “fix bug” and “test” are slowing your team down When you’re in the middle of solving a bug or building a feature, it's tempting to hit: git commit -m "test" git commit -m "test" Or worse: git commit -m "fix" git commit -m "fix" You’re moving fast. You just want to save your progress. But over time, this creates a real mess. Let’s break down what actually goes wrong. 1. “Fix bug” and “test” Everywhere Scroll through a commit log on a real project and you’ll often see: commit 8d12a3c - fix commit 4cfa33e - test commit a7b84fe - more fixes commit f1dc990 - test again commit 8d12a3c - fix commit 4cfa33e - test commit a7b84fe - more fixes commit f1dc990 - test again None of these tell you what changed, or why. what changed why And if something breaks? You’re left guessing: What did this commit fix? What was the original bug? What part of the system was involved? What did this commit fix? What was the original bug? What part of the system was involved? It's like trying to read a story when every chapter is titled “Chapter”. “Chapter” 2. Hard to Track What Actually Changed Imagine you're debugging a production issue two months later. You run git blame and land on this: git blame // dashboard.js renderData(); // added in commit 8d12a3c - "fix" // dashboard.js renderData(); // added in commit 8d12a3c - "fix" Now you have to: Manually check the diff Hope the PR has context Maybe guess what the "fix" was about Manually check the diff Hope the PR has context Maybe guess what the "fix" was about Compare that to this: git commit -m "Fix: prevent empty data crash in dashboard view" git commit -m "Fix: prevent empty data crash in dashboard view" Now you immediately know:→ What the change was→ Why it happened→ Where to look next if something else goes wrong Good commit messages are breadcrumbs for your future self. breadcrumbs for your future self 3. Painful Future Debugging Bad commits don’t just waste time. They cause bugs to go unnoticed longer. Here’s an example: git log commit 5a8b13a - "test new filter" commit 64fef21 - "update" commit a4d9e7c - "trying something" git log commit 5a8b13a - "test new filter" commit 64fef21 - "update" commit a4d9e7c - "trying something" Now the QA team finds a regression. Which commit caused it? What exactly changed in “update”? Is “trying something” safe to revert? You won’t know—until you manually inspect every one. With clean commits, this becomes much easier: commit 84f2ad3 - "Refactor: simplify filter logic for multi-select dropdown" commit c73f8da - "Fix: prevent crash on empty filter array" commit 84f2ad3 - "Refactor: simplify filter logic for multi-select dropdown" commit c73f8da - "Fix: prevent crash on empty filter array" You can now: Use git bisect with confidence Revert specific logic without breaking others Understand intent just from the commit log Use git bisect with confidence git bisect Revert specific logic without breaking others Understand intent just from the commit log Quick Tip: What a Clean Commit Looks Like Bad: git commit -m "fix" git commit -m "fix" Better: git commit -m "Fix: prevent null value from breaking pagination" git commit -m "Fix: prevent null value from breaking pagination" Even better if paired with structured commits (like Conventional Commits): fix(api): handle undefined query param in /users endpoint fix(api): handle undefined query param in /users endpoint This tells the story clearly and consistently. And when paired with automation (e.g., changelogs or releases), it’s powerful. The Takeaway Messy commits feel fast in the moment. But they cost you clarity, time, and trust later. clarity, time, and trust Avoid:→ One-word commits→ Meaningless messages like “temp” or “test”→ Piling unrelated changes into a single commit Do:→ Write why something changed—not just what→ Keep commits small and focused→ Use consistent naming (e.g., Fix:, Refactor:, Add:) why what Fix: Refactor: Add: Good commits don’t just save time. They make your repo understandable—for you, your teammates, and even strangers months from now. make your repo understandable Adopting a Clean Commit Strategy Because “fixed stuff” isn’t helpful six months from now Because “fixed stuff” isn’t helpful six months from now Your commit history tells the story of your codebase. And like any story, it’s either:→ Clear and helpful→ Or messy and hard to follow We’ve all seen (or written) commits like this: git commit -m "fix" git commit -m "wip" git commit -m "final final fix" git commit -m "fix" git commit -m "wip" git commit -m "final final fix" They make sense in the moment. But later? When you're debugging a regression? They’re worthless. Here’s how we cleaned up our commit habits—and made our history readable, searchable, and actually useful. 1. Write Commits Like You’ll Read Them in 6 Months Write Commits Like You’ll Read Them in 6 Months A good commit message is like a headline. It tells you what changed and why, without opening the diff. without opening the diff. Bad: git commit -m "Update" git commit -m "Update" Better: git commit -m "Fix spacing issue in mobile nav" git commit -m "Fix spacing issue in mobile nav" Even better: git commit -m "Fix mobile nav layout: add responsive gap between links" git commit -m "Fix mobile nav layout: add responsive gap between links" That second version tells you: What changed (layout fix) Where (mobile nav) Why (gap between links) What changed (layout fix) Where (mobile nav) Why (gap between links) **Rule of thumb:**If your commit shows up in git blame, will someone understand what happened? git blame 2. Commit Only What Matters Commit Only What Matters Sometimes, we commit everything out of habit. Even console logs, temporary experiments, or unrelated test files. That bloats the history and hides the real changes. real Before committing, ask: Before committing, ask: Does this change belong here? Is this related to the current task? Is this debug code I forgot to remove? Does this change belong here? Is this related to the current task? Is this debug code I forgot to remove? Use git add -p (patch mode) to stage changes interactively: git add -p git add -p git add -p This lets you commit only the relevant parts of a file. Example: You fixed a button style and added a new logging function in the same file. Use patch mode to commit only the style fix: and git commit -m "Fix button hover state on Safari" git commit -m "Fix button hover state on Safari" Then stage the log function separately: git commit -m "Add debug log for checkout process" git commit -m "Add debug log for checkout process" Now your commits are clean, atomic, and easier to roll back or review. 3. Group Related Changes Together Group Related Changes Together Each commit should represent a single unit of change. Avoid this: Avoid this: git commit -m "Refactor card component and add analytics and fix dark mode" git commit -m "Refactor card component and add analytics and fix dark mode" This does three different things: three A UI refactor An analytics feature A bug fix A UI refactor An analytics feature A bug fix If something breaks, which part was responsible? Instead, break it into three commits: git commit -m "Refactor <Card> layout for cleaner spacing" git commit -m "Add click tracking to <Card> CTA button" git commit -m "Fix dark mode background for <Card>" git commit -m "Refactor <Card> layout for cleaner spacing" git commit -m "Add click tracking to <Card> CTA button" git commit -m "Fix dark mode background for <Card>" Now if dark mode breaks again, you know exactly where to look. And if analytics needs to be rolled back? You can revert that commit without touching the others. Bonus: Use Conventional Commit Patterns (if you work in a team) If you want structure, consider using Conventional Commits: Conventional Commits feat: add new pricing card layout fix: resolve mobile spacing issue in <Header> refactor: clean up form logic for <Checkout> feat: add new pricing card layout fix: resolve mobile spacing issue in <Header> refactor: clean up form logic for <Checkout> These patterns make changelogs easier to automated make the purpose of each change clearer at a glance. The Takeaway Good commit hygiene pays off over time. You:→ Save your future self (and teammates) hours of debugging→ Make PRs easier to review→ Reduce fear when refactoring A clean commit history isn’t about perfection. It’s about respecting the story of your project—so you can understand it later. respecting the story of your project So write commits like they matter. Because when you’re trying to undo a bug in six months, they really do. So write commits like they matter. Using Git Effectively During Development How to stage, fix, and clean up your commits like a pro How to stage, fix, and clean up your commits like a pro Most developers use Git just enough to get by:git add ., git commit -m "something", git push. git add . git commit -m "something" git push It works. But it also leads to messy histories, mixed changes, and hard-to-review PRs. Here are 3 simple Git techniques that can drastically improve your development workflow—without adding complexity. 1. git add -p – Stage Only What You Mean To git add -p You made changes to multiple things:– Fixed a bug– Added a log statement– Tweaked some spacing– Wrote a new feature You don't want to commit all of that in one blob. That's where git add -p helps. git add -p git add -p git add -p It breaks your changes into small “hunks” and lets you interactively pick what to stage: small “hunks” Stage this hunk [y,n,q,a,d,s,e,?]? Stage this hunk [y,n,q,a,d,s,e,?]? y: yes, stage this part n: no, skip this part s: split into smaller parts e: manually edit the change before staging y: yes, stage this part y n: no, skip this part n s: split into smaller parts s e: manually edit the change before staging e Example Workflow: git add -p git commit -m "Fix header spacing issue" git add -p git commit -m "Refactor auth logic" git add -p git commit -m "Fix header spacing issue" git add -p git commit -m "Refactor auth logic" Now your commits are focused, readable, and easy to review. 2. git commit --amend – Fix Your Last Commit git commit --amend Just made a commit but forgot something? Or noticed a typo in the message? No need to make a second “fix” commit. Just amend the last one: git commit --amend git commit --amend By default, this: Opens your editor to modify the commit message Includes any newly staged changes in the same commit Opens your editor to modify the commit message Includes any newly staged changes in the same commit Example 1: Fix the commit message git commit --amend -m "Fix navbar link alignment" git commit --amend -m "Fix navbar link alignment" Example 2: Add a forgotten file git add nav.css git commit --amend git add nav.css git commit --amend Now your history stays clean—no noisy "oops" commits. 3. git rebase -i – Clean Up Before You Push git rebase -i After a day of work, your commit history might look like this: [fix bug] [console.log] [add real fix] [update style] [rename file] [fix bug] [console.log] [add real fix] [update style] [rename file] Before pushing to the shared repo, use git rebase -i to clean it up: git rebase -i git rebase -i HEAD~5 git rebase -i HEAD~5 You’ll see: pick 3f1a8f2 fix bug pick 7ab3e9c console.log pick 5ca9c11 add real fix pick b7e1dd4 update style pick 0db1ae2 rename file pick 3f1a8f2 fix bug pick 7ab3e9c console.log pick 5ca9c11 add real fix pick b7e1dd4 update style pick 0db1ae2 rename file Now you can: Change pick to squash to merge commits Reorder commits Edit commit messages Change pick to squash to merge commits pick squash Reorder commits Edit commit messages Example: squash the "console.log" into the "fix bug" commit: pick 3f1a8f2 fix bug squash 7ab3e9c console.log pick 5ca9c11 add real fix ... pick 3f1a8f2 fix bug squash 7ab3e9c console.log pick 5ca9c11 add real fix ... After saving, you’ll be prompted to edit the combined commit message. This keeps your branch history clean, logical, and meaningful—especially before opening a PR. The Takeaway Git isn’t just for saving code. It’s for communicating intent. Using these tools helps you:→ Stage only what matters→ Avoid noisy fix commits→ Keep your commit history clean and reviewable It’s not about perfection—it’s about clarity. Start with one small habit, like git add -p, and build from there. Your future self—and your teammates—will thank you. git add -p Avoiding Commit Spam Why “commit often” doesn’t mean “commit everything” Why “commit often” doesn’t mean “commit everything” You’ve probably heard the advice: “Commit early, commit often.” “Commit early, commit often.” That’s true—but only if your commits are meaningful. Because when you push 17 commits like this: fix spacing remove console.log update var name final fix I swear another tweak formatting fix spacing remove console.log update var name final fix I swear another tweak formatting …you’re not helping anyone. You're creating commit spam—noisy history that’s hard to read, review, or roll back. commit spam Clean commit history matters. It’s the story of your project. story of your project Let’s look at how to avoid spam and keep commits useful. 1. Why “Commit Often” Is Misunderstood The goal of committing often is to: Save work at meaningful points Break up features into reviewable chunks Make rollbacks safer Save work at meaningful points Break up features into reviewable chunks Make rollbacks safer It doesn’t mean you should commit every time you press save. every time you press save A commit should represent a logical unit of work—not just a moment in time. logical unit of work ✅ Good commits: feat: add responsive navbar with mobile drawer fix: prevent crash on empty user input chore: remove unused dependency from package.json feat: add responsive navbar with mobile drawer feat: add responsive navbar with mobile drawer fix: prevent crash on empty user input fix: prevent crash on empty user input chore: remove unused dependency from package.json chore: remove unused dependency from package.json 🚫 Bad commits: fix again remove debug log tiny change oops fix again fix again remove debug log remove debug log tiny change tiny change oops oops These don’t tell the next dev (or future you) why the change happened or what it solved. why 2. Avoid Committing Noise Formatting, console logs, and linter fixes aren’t “features. ”They clutter your history and make it harder to spot real changes. Bad example: Bad example: git add . git commit -m "fix bug in homepage" git commit -am "remove console.log" git commit -am "run Prettier" git add . git commit -m "fix bug in homepage" git commit -am "remove console.log" git commit -am "run Prettier" These could be a single commit: single commit git commit -am "fix: remove console logs and fix homepage rendering bug" git commit -am "fix: remove console logs and fix homepage rendering bug" What helps: What helps: Run formatters before you commit Remove console/debug logs as part of your real change Use .gitignore to skip auto-generated files and build output Run formatters before you commit before Remove console/debug logs as part of your real change as part of your real change Use .gitignore to skip auto-generated files and build output .gitignore 3. Use Staging Wisely You don’t have to commit everything at once. Use git add -p or a GUI to stage changes selectively. everything git add -p selectively git add -p git add -p This lets you: Group related changes together Exclude debugging leftovers Keep commits focused and clean Group related changes together Exclude debugging leftovers Keep commits focused and clean If you're working in VS Code, use the Source Control sidebar to stage only what matters. 4. Clean It Up Before You Push It’s fine to make messy commits while working. But before you open a pull request or merge into main, clean up the history: clean up the history Option 1: Squash commits in your PR (GitHub/Bitbucket UI) This turns: feat: start sidebar fix sidebar width remove temp logs final fix before merge feat: start sidebar fix sidebar width remove temp logs final fix before merge into: feat: add responsive sidebar layout feat: add responsive sidebar layout Option 2: Use interactive rebase git rebase -i HEAD~4 git rebase -i HEAD~4 Pick the commit to keep. Squash the rest. Write a clear message. Now your branch looks clean—and easier for reviewers to understand. Summary: Best Practices for Commit Hygiene ✅ Do This 🚫 Avoid This Commit logically grouped changes Commit every single file edit Use clear commit messages Messages like “fix again” or “update” Run formatters/lint before staging Committing auto-formatting as separate noise Stage changes intentionally Blindly git add . every time Squash or rebase before pushing Letting 15 noisy commits hit main ✅ Do This 🚫 Avoid This Commit logically grouped changes Commit every single file edit Use clear commit messages Messages like “fix again” or “update” Run formatters/lint before staging Committing auto-formatting as separate noise Stage changes intentionally Blindly git add . every time Squash or rebase before pushing Letting 15 noisy commits hit main ✅ Do This 🚫 Avoid This ✅ Do This ✅ Do This 🚫 Avoid This 🚫 Avoid This Commit logically grouped changes Commit every single file edit Commit logically grouped changes Commit logically grouped changes Commit every single file edit Commit every single file edit Use clear commit messages Messages like “fix again” or “update” Use clear commit messages Use clear commit messages Messages like “fix again” or “update” Messages like “fix again” or “update” Run formatters/lint before staging Committing auto-formatting as separate noise Run formatters/lint before staging Run formatters/lint before staging Committing auto-formatting as separate noise Committing auto-formatting as separate noise Stage changes intentionally Blindly git add . every time Stage changes intentionally Stage changes intentionally Blindly git add . every time Blindly git add . every time git add . Squash or rebase before pushing Letting 15 noisy commits hit main Squash or rebase before pushing Squash or rebase before pushing Letting 15 noisy commits hit main Letting 15 noisy commits hit main Remember: Commits are more than snapshots. They’re how your team learns from the past, tracks progress, and reviews code efficiently. A clean commit history saves time, builds trust, and makes collaboration smoother. Remember: So yes—commit often. But commit with care. commit with care. Best Practices for Side Projects Because solo ≠ sloppy Because solo ≠ sloppy Side projects are where we experiment, learn, and build without pressure. But that doesn’t mean we should throw away good habits. In fact, the way you treat your side projects often mirrors how you'll work in production. Clean habits here lead to better outcomes later—especially when your project grows or becomes public. Let’s talk about a few simple practices that keep your side projects fast, clean, and ready to ship. 1. Use Feature Branches — Even When Working Solo It’s tempting to push everything to main. main But using feature branches helps: Keep your changes scoped Make it easier to track what you’re working on Avoid breaking something that’s already working Keep your changes scoped Make it easier to track what you’re working on Avoid breaking something that’s already working Example workflow: Example workflow: git checkout -b feat/login-form git checkout -b feat/login-form Make your changes, then commit and push: git add . git commit -m "Add basic login form with validation" git push origin feat/login-form git add . git commit -m "Add basic login form with validation" git push origin feat/login-form Once it works, merge into main: main git checkout main git merge feat/login-form git push origin main git checkout main git merge feat/login-form git push origin main Even if you're working alone, this gives you:→ A cleaner commit history→ A safer rollback path→ Better organization as the codebase grows And if you open source the project later? You’ve already built the habit of clean collaboration. 2. Keep Your Main Branch Deploy-Ready Treat main like production—even for side projects. main That means: No broken builds No experimental half-finished features No console logs everywhere No broken builds No experimental half-finished features No console logs everywhere This makes it easy to: Deploy to Vercel / Netlify without thinking Demo your project to friends, clients, or future employers Roll back safely if something goes wrong Deploy to Vercel / Netlify without thinking Demo your project to friends, clients, or future employers Roll back safely if something goes wrong Tip: Set up GitHub Actions or another CI tool to test your build on every push to main. Tip: main # .github/workflows/ci.yml name: Build Check on: push: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install deps run: npm install - name: Run build run: npm run build # .github/workflows/ci.yml name: Build Check on: push: branches: [ main ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install deps run: npm install - name: Run build run: npm run build Now if your build fails, you’ll catch it early—before pushing something broken live. 3. Write Meaningful Commit Messages Your commits are your timeline. Don’t make it read like: fix update stuff final changes fix update stuff final changes Instead, write messages that explain what you did and why it matters. Good examples: Good examples: feat: add dark mode toggle with system preference support fix: handle empty email input in signup form refactor: simplify navbar layout for better responsiveness feat: add dark mode toggle with system preference support fix: handle empty email input in signup form refactor: simplify navbar layout for better responsiveness This pays off when: You revisit the project after months You're debugging something odd Someone else wants to contribute You revisit the project after months You're debugging something odd Someone else wants to contribute You can even follow a consistent convention like Conventional Commits: Conventional Commits git commit -m "feat: add local storage hook for user preferences" git commit -m "feat: add local storage hook for user preferences" It makes changelogs easier and helps automation tools later if your project grows. The Takeaway Even if it’s a solo project, treat it like it matters. → Use branches so you don’t break your base→ Keep main clean so deploys are easy→ Write clear commits so future-you isn’t lost main These small habits don’t slow you down. They actually help you move faster, with fewer mistakes—and more confidence. Because every great product started as a side project someone took seriously. Sample Commit Message Templates How to write clear, consistent, and useful commit messages How to write clear, consistent, and useful commit messages Good commit messages are more than a nice-to-have. They improve collaboration, simplify debugging, and make tools like git log, changelogs, and CI pipelines far more useful. git log But many teams still treat commits like an afterthought. So here’s how to fix that—without overthinking it. Why Use Commit Message Conventions? A structured commit history helps you: ✅ Understand what changed at a glance ✅ Auto-generate changelogs ✅ Trigger semantic releases ✅ Keep pull requests clean and readable ✅ Reduce noise when debugging We follow a common convention called Conventional Commits, where each commit starts with a prefix: Conventional Commits prefix <type>(optional scope): description <type>(optional scope): description Common Prefixes and What They Mean Prefix Use it when... feat: You’re adding a new feature fix: You’re fixing a bug chore: You’re doing non-feature work (build scripts, config) refactor: You’re improving code without changing behavior docs: You’re updating documentation only style: You’re updating formatting, spacing, or linting only test: You’re adding or updating tests perf: You’re improving performance Prefix Use it when... feat: You’re adding a new feature fix: You’re fixing a bug chore: You’re doing non-feature work (build scripts, config) refactor: You’re improving code without changing behavior docs: You’re updating documentation only style: You’re updating formatting, spacing, or linting only test: You’re adding or updating tests perf: You’re improving performance Prefix Use it when... Prefix Prefix Use it when... Use it when... feat: You’re adding a new feature feat: feat: feat: You’re adding a new feature You’re adding a new feature fix: You’re fixing a bug fix: fix: fix: You’re fixing a bug You’re fixing a bug chore: You’re doing non-feature work (build scripts, config) chore: chore: chore: You’re doing non-feature work (build scripts, config) You’re doing non-feature work (build scripts, config) refactor: You’re improving code without changing behavior refactor: refactor: refactor: You’re improving code without changing behavior You’re improving code without changing behavior docs: You’re updating documentation only docs: docs: docs: You’re updating documentation only You’re updating documentation only style: You’re updating formatting, spacing, or linting only style: style: style: You’re updating formatting, spacing, or linting only You’re updating formatting, spacing, or linting only test: You’re adding or updating tests test: test: test: You’re adding or updating tests You’re adding or updating tests perf: You’re improving performance perf: perf: perf: You’re improving performance You’re improving performance ✅ Practical Examples You Can Copy Here are some commit templates you can start using right now. 🚀 Features feat(auth): add JWT-based login flow feat(ui): support dark mode toggle in header feat(api): expose /reports endpoint for analytics feat(auth): add JWT-based login flow feat(ui): support dark mode toggle in header feat(api): expose /reports endpoint for analytics 🐛 Bug Fixes fix(form): prevent double submission on enter key fix(auth): handle expired token redirect properly fix(api): correct timezone offset in report results fix(form): prevent double submission on enter key fix(auth): handle expired token redirect properly fix(api): correct timezone offset in report results 🧹 Chores and Maintenance chore: update dependencies chore(lint): apply prettier formatting chore(ci): add GitHub Actions workflow for tests chore: update dependencies chore(lint): apply prettier formatting chore(ci): add GitHub Actions workflow for tests 🛠 Refactoring refactor(modal): simplify open/close logic refactor(routes): use centralized route config refactor(modal): simplify open/close logic refactor(routes): use centralized route config 📚 Docs docs(readme): clarify setup steps docs: add usage examples for CLI commands docs(readme): clarify setup steps docs: add usage examples for CLI commands 🧪 Tests test(api): add tests for auth middleware test(button): ensure loading state is rendered test(api): add tests for auth middleware test(button): ensure loading state is rendered ⚡️ Performance perf(list): memoize filtered results perf: avoid unnecessary re-renders on scroll perf(list): memoize filtered results perf: avoid unnecessary re-renders on scroll 💡 Bonus: Use Scopes for Clarity Adding a scope in parentheses can make large projects easier to navigate. Example: feat(user-settings): allow profile image upload fix(auth): reset state on logout chore(deps): bump react from 18.1.0 to 18.2.0 feat(user-settings): allow profile image upload fix(auth): reset state on logout chore(deps): bump react from 18.1.0 to 18.2.0 Think of the scope as the “area of code” you’re touching. How to Use These in Practice When writing a commit: Start with the right prefix Use the imperative mood (e.g. “add feature”, not “added feature”) Keep it short and specific Optionally add a description body: Start with the right prefix Start with the right prefix Use the imperative mood (e.g. “add feature”, not “added feature”) Use the imperative mood Keep it short and specific Keep it short and specific Optionally add a description body: feat(nav): add mobile menu Allows navigation drawer toggle on smaller screens. Accessible via hamburger icon. feat(nav): add mobile menu Allows navigation drawer toggle on smaller screens. Accessible via hamburger icon. This extra context is helpful when reviewing git log or PRs. git log The Takeaway Clear commit messages pay off later—when you're debugging, writing changelogs, or explaining a decision six months from now. Start with just this: feat: new feature fix: bug fix chore: internal changes feat: new feature fix: bug fix chore: internal changes Then expand as your team grows. Good commit hygiene is like good code style: invisible when done right, painful when ignored. Conclusion Keeping history clean so your future self doesn’t suffer Keeping history clean so your future self doesn’t suffer When you’re in the zone, shipping features fast, it’s easy to overlook one thing: your project history. project history But fast-forward a few months—or worse, a year—and someone (probably you) will ask: “Why was this changed? ”“What was the bug here again? ”“Who wrote this and what were they thinking?” “Why was this changed? ”“What was the bug here again? ”“Who wrote this and what were they thinking?” Clean commit history and clear code changes aren’t just good habits. They’re future-proofing for your team—and your future self. future-proofing Think of Your Git Log as a Story The worst git history looks like this: commit 7ae8d2d - "fix" commit 114bc9a - "debug" commit f12d10e - "oops" commit 3a5e22f - "final version" commit 7ae8d2d - "fix" commit 114bc9a - "debug" commit f12d10e - "oops" commit 3a5e22f - "final version" It’s unsearchable, untraceable, and useless. A clean history tells a story: commit e89c4b2 - "Add input validation to user form" commit 5a93db7 - "Fix timezone parsing bug in booking calendar" commit 4e32d17 - "Refactor dashboard layout into reusable grid system" commit e89c4b2 - "Add input validation to user form" commit 5a93db7 - "Fix timezone parsing bug in booking calendar" commit 4e32d17 - "Refactor dashboard layout into reusable grid system" Each commit should answer: What changed Why it changed Optionally, what it fixes or relates to What changed What changed Why it changed Why it changed Optionally, what it fixes or relates to what it fixes or relates to Use Atomic Commits Don’t lump 10 changes into one commit. Bad: commit 2410adb - "update styles, fix button, add tests, remove logs" commit 2410adb - "update styles, fix button, add tests, remove logs" Good: commit b67f9c1 - "Remove unused console logs in Dashboard" commit d21a1b9 - "Fix button alignment on mobile in Header" commit a42ebd4 - "Add unit tests for NavBar collapse behavior" commit b67f9c1 - "Remove unused console logs in Dashboard" commit d21a1b9 - "Fix button alignment on mobile in Header" commit a42ebd4 - "Add unit tests for NavBar collapse behavior" Atomic commits:→ Make it easier to revert specific changes→ Keep pull requests readable→ Help reviewers (and future devs) spot regressions fast Code Comments That Age Well You don’t need to explain what the code does (that’s what the code is for).But you should explain why it’s done that way—especially if it’s a workaround. what why // Avoid using `getDate()` here due to DST shift on March 9 const tomorrow = new Date(date); tomorrow.setDate(date.getDate() + 1); // Avoid using `getDate()` here due to DST shift on March 9 const tomorrow = new Date(date); tomorrow.setDate(date.getDate() + 1); That kind of note saves hours of future debugging. Squash Before Merging (When It Makes Sense) Feature branches can get messy: commit b0d… - "start dropdown" commit b1e… - "make it blue" commit b2f… - "revert blue, try gray" commit b3g… - "fix shadow on hover" commit b0d… - "start dropdown" commit b1e… - "make it blue" commit b2f… - "revert blue, try gray" commit b3g… - "fix shadow on hover" Before merging to main, squash those into one clean commit: main "Add responsive dropdown with gray styling and hover effects" "Add responsive dropdown with gray styling and hover effects" It keeps your main branch professional and searchable. Your Future Self Will Thank You Clean history isn't for perfection. It's for debugging, onboarding, and understanding the past. debugging, onboarding, and understanding the past Next time you're:→ Blaming a random change→ Rewriting a component→ Untangling a merge conflict→ Asking "why is this here?" A clean history gives you the answers. Final Tip: Treat Code Like a Journal Write it like someone else will read it tomorrow. Because someone will. And 90% of the time—that person is you. you So leave them a map.