On a recent project, my client had a firm rule: one commit per pull request. No exceptions.
At first, it seemed like a minor constraint. But it quickly pushed me to get comfortable with a handful of Git commands I’d been using only occasionally: git commit, git rebase, and git reset –soft. Each one solves a slightly different problem, and knowing when to reach for which one has made me a much more intentional developer.
git commit: The Foundation
Everything starts here. A commit snapshots your staged changes and stores them in history. The key discipline with single-commit pull requests is being intentional about when you commit and what message you write.
If you’re aiming for a single clean commit, the best-case scenario is working in a focused enough way that you stage and commit once when the work is truly done:
git add . git commit -m "Add user authentication via OAuth"
In practice, though, most of us commit frequently as we work. Saving progress, testing ideas, checking in before a risky change. That’s fine. The other commands are there to help you clean up before you open the PR.
git commit –amend: Fix the Last Commit
Sometimes you don’t need to collapse multiple commits — you just need to fix the most recent one. Maybe you forgot to stage a file, spotted a typo in the code, or want to reword your commit message. That’s where –amend comes in.
git add forgotten-file.ts git commit --amend
This replaces the last commit with a new one that includes your staged changes. Your editor will open so you can update the message too. If you only want to fix the message and not add any new changes:
git commit --amend -m "Better commit message here"
It’s the lightest-weight option in this toolkit — no rebasing, no resetting, just a quick correction to the tip of your branch.
When to use it: When your last commit is almost right but not quite. If you need to fix something two or more commits back, reach for git rebase -i instead.
The same caution applies: Amend rewrites the last commit, so if you’ve already pushed that commit to a remote branch, you’ll need to force-push:
git push --force-with-lease
git reset –soft: Undo Commits, Keep Your Work
git reset –soft is your best friend when you’ve made several commits and want to collapse them into one without losing any of your changes. It moves the HEAD pointer back to a previous commit, but leaves your working directory and staging area untouched.
Say you’ve made three commits on your feature branch:
git reset --soft HEAD~3
Now those three commits are gone from history, but all the changes they contained are still staged and ready to go. You can then make one clean commit:
git commit -m "Add user authentication via OAuth"
This is the approach I reach for most often. It’s simple, hard to mess up, and gives you full control over the final commit message.
When to use it: When you want to squash your recent commits into one before pushing, and you’re working on a branch only you’ve touched.
git rebase -i: Surgical Commit History Editing
Interactive rebase is more powerful and more involved. It lets you rewrite, reorder, edit, and squash commits across your branch’s entire history relative to another branch.
git rebase -i main
This opens an editor showing every commit on your branch since it diverged from main. Each line represents a commit, and you can change the action prefix:
- pick — keep the commit as-is
- squash (or s) — combine this commit with the one above it
- reword — keep the changes, but edit the message
- drop — remove the commit entirely
To squash everything into one commit, change all but the first pick to squash, save, and Git will walk you through writing the combined commit message.
When to use it: When you need finer control, such as, reordering commits, editing messages mid-history, or selectively squashing only some commits rather than all of them.
A word of caution: Rebase rewrites history. Never rebase commits that have already been pushed to a shared branch unless you’re prepared to force-push and coordinate with your team.
Which Should You Use?
| Situation | Best Tool |
| Fix the most recent commit | git commit –amend |
| Collapse recent commits simply | git reset –soft |
| Need to reorder or edit mid-history | git rebase -i |
| Merging a PR with one commit via GitHub | Squash and merge button |
| Starting fresh from scratch | git reset –soft HEAD~N + recommit |
The single-commit-per-PR rule felt constraining at first, but it’s pushed me to write clearer commit messages and think more deliberately about when a piece of work is actually done. Getting fluent with reset –soft and interactive rebase is a small investment that pays off quickly, both for keeping your own history clean and for being a better collaborator on teams that care about a readable Git log.