I commit constantly. After every passing test, every completed function, every logical checkpoint. Here's why.

The Anti-Pattern

End-of-day commits:

commit abc123
Author: Developer
Date: Friday 6pm

    WIP: lots of changes
    
    - Added user auth
    - Fixed bug in payments
    - Refactored database layer
    - Updated tests
    - Changed config format

500 lines changed. Five unrelated things. Good luck reviewing that.

The Better Way

Incremental commits:

commit def456: feat: add password validation to signup
commit ghi789: fix: handle null user in payment flow  
commit jkl012: refactor: extract database connection pool
commit mno345: test: add coverage for auth edge cases
commit pqr678: config: switch to YAML format

Each commit is one logical change. Each can be reviewed, reverted, or cherry-picked independently.

Why It Matters

Easier Code Review

Reviewers can understand one change at a time. "This commit adds validation" is reviewable. "This commit does five things" isn't.

Safer Reverts

Something broke? git bisect finds the exact commit. Revert it. Done.

With giant commits, reverting means losing good changes along with the bad.

Better History

Six months later, "why does this code exist?" The answer is in the commit message—if each commit is focused enough to have a clear message.

Psychological Checkpoints

Each commit is progress. Stuck on a hard problem? At least your last three small wins are saved.

When to Commit

After:

  • A test passes
  • A function works
  • A bug is fixed
  • A refactor is complete
  • Any logical unit of work

Before:

  • Switching to a different task
  • Taking a break
  • Ending the day

The question isn't "is this big enough to commit?" It's "is this a coherent change?"

What Makes a Good Commit

One thing. Not "add feature and fix bug and refactor." One thing.

Working state. Tests pass. Code compiles. Don't commit broken code.

Clear message. Future you should understand what changed and why.

feat: add rate limiting to API endpoints

Adds a sliding window rate limiter to prevent abuse.
Limit: 100 requests per minute per IP.

Closes #234

The Fear

"But my history will be messy!"

Squash before merging if you want clean history. The messy incremental commits are your development log. The squashed merge is the official record.

"But I'll commit too often!"

There's no such thing. You can always squash later. You can't un-squash a giant commit.

"But it's slower!"

git commit -m "message" takes two seconds. The time you save debugging and reviewing dwarfs the commit overhead.

My Actual Flow

  1. Make a small change
  2. Run tests
  3. If tests pass: git add -p && git commit -m "description"
  4. Repeat

The -p flag lets me stage hunks interactively. Even within one file, I can split changes into separate commits.

Habits That Help

Commit messages first. Write the message, then make the change. If you can't write a clear message, the change might not be focused enough.

Atomic changes. Don't mix refactoring with features. Refactor first, commit. Add feature, commit.

Work in progress is okay. WIP: trying new approach is fine—just squash before merging.

Push frequently. Commits on your machine aren't safe. Push to remote regularly.

The Compound Effect

Good commit habits compound. Clean history makes code review faster. Faster review means faster merging. Faster merging means less divergence. Less divergence means fewer conflicts.

Small commits → fast reviews → quick merges → smooth collaboration.

Start small. Commit often. Your future self will thank you.

React to this post: