How I Messed up a PR—and How You Can Write Better Git Commit Messages

June 12, 2025 · ~1,000 words


The Day I Deleted My Own PR

It was a bright Thursday morning when I decided to add password hashing to our FastAPI backend. I wrote a quick utility in utils/password.py, updated the signup endpoint, tweaked the README and pushed my branch:

git add utils/ api/ README.md requirements.txt
git commit -m "Defined a function to hash a password using the bcrypt algorithm."
git push -u origin hashpassword

Moments later, I opened the pull request and froze. My commit message was a long, rambling sentence in past tense and I’d split related tweaks into three tiny commits:

  1. Add bcrypt password utils and Google ID token verification

  2. Update README with X changes

  3. Removed google.py

On GitHub, the PR looked messy. The commit log was cluttered, the message was wordy and I had even included a stray endpoint file I didn’t intend to ship. In a moment of panic, I deleted the PR, determined to start over with a clean slate.

Little did I know, that “fresh start” would teach me the single most important skill in collaborative Git: how to write clear, consistent commit messages so that future-me and your teammates never need to delete a PR again.


Why Commit Messages Matter

A good commit message is more than a note to yourself. It’s a promise to everyone else on the project:

  • Context for Reviewers
    A concise message helps reviewers understand what you changed and why before they dive into the diff.

  • Readable History
    Ten commits titled “Fix stuff” teach you nothing when you’re bisecting a bug six months later.

  • Automation & Tooling
    Structured messages fuel changelog generators, semantic-release workflows and commit-lint checks.

Nail your commit messages up front and you’ll avoid awkward PR deletions, rebase meltdowns and frantic late-night force-pushes.


My Fresh Start: The One-Commit PR

Here’s the “start-from-scratch” workflow I used to rescue my feature:

  1. Kill the old branch

     git branch -D hashpassword
    
  2. Reset main to match origin

     git checkout main
     git fetch origin
     git reset --hard origin/main
    
  3. Create a brand-new branch

     git checkout -b add-password-hashing
    
  4. Re-apply only the polished changes

    • utils/api.py with bcrypt helpers

    • cleaned-up README.md and requirements.txt

  5. Stage just those files

     git add utils/api.py README.md requirements.txt
    
  6. Write a single and crisp commit message

     git commit -m "Add bcrypt password-hashing utility and update docs"
    
  7. Push & open a new PR

     git push -u origin add-password-hashing
    

Voilà—one branch, one commit, one clear message. No PR deletions required.


Anatomy of a Great Commit Message

Whether you’re on a solo side-project or a 50-person team, these principles will level up your Git game:

  1. Keep the subject ≤ 50 characters
    Shorter is sweeter. It fits in logs and GUI displays without wrapping.

  2. Use imperative present tense
    Write it like a command that Git will execute when applied:

    | Bad (past tense) | Good (imperative) | | --- | --- | | Defined a function to hash passwords | Add function to hash passwords | | Updated README installation section | Update README installation steps | | Removed deprecated Google module | Remove deprecated Google module |

  3. Separate subject from body with a blank line
    If you need more context, follow the subject with a paragraph explaining the why:

     Add bcrypt password-hashing utility and update docs
    
     Use bcrypt with a work factor of 12 for stronger security.
     Clarify installation steps in README to include the new dependency.
    
  4. Wrap the body at ~72 characters
    Keeps your text readable in terminals and code-review tools alike.

  5. No trailing period on the subject
    That little dot wastes precious characters and can look inconsistent.


Leveling Up: Conventional Commits

If your team wants even more structure—automated changelogs, semantic-release, commit-lint ,you can adopt the Conventional Commits spec:

<type>(<scope>): <subject>

<body>

<footer>
  • type: feat (new feature), fix (bug fix), docs, style, refactor, perf, test, chore

  • scope (optional): area of the codebase, e.g. auth, db, api

  • subject: imperative, ≤50 characters

  • footer: references (Closes #123), breaking changes

Example

feat(auth): add bcrypt password-hashing utility

Use bcrypt with strength 12 to protect user passwords
and update README with installation instructions.

Closes #42

Conventional Commits empower tools to:

  • Auto-generate your CHANGELOG.md

  • Bump versions semantically (feat → minor, fix → patch)

  • Enforce commit-message policies via CI


Putting It All Together

Before you hit git commit, run through this checklist:

  1. Branch
    Create a dedicated feature branch—never commit directly to main.

  2. Stage thoughtfully
    Only git add the files relevant to this logical change.

  3. Write your subject

    • Imperative, present tense

    • ≤50 characters

    • No trailing period

  4. Add a body (if needed)
    Explain why you made this change, not what you changed.

  5. Use Conventional Commits (optional)
    Prefix with feat(scope): or fix: if your project uses them.

  6. Rebase or merge main frequently
    Keep your branch up to date to avoid conflict headaches.

  7. Squash related work
    Collapse WIP commits or tiny fix-ups into a single, unified commit before opening your PR.


Final Thoughts

Deleting that first PR stung but the clean branch and well-crafted commit message that replaced it saved hours of confusion for both me and my reviewers. Today, I treat every commit as an entry in our project’s story-clear, concise and purposeful.

Next time you find yourself staring at a messy PR, remember: it’s not about deleting work, it’s about writing it right. Commit with intention and your future self will thank you.

Happy coding (and committing)! 🚀

0
Subscribe to my newsletter

Read articles from Ganiyatu Sanuusi directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Ganiyatu Sanuusi
Ganiyatu Sanuusi

Tech with Ghaniya is a space where I share real-world solutions to tech problems I’ve faced — and go further by offering practical tips, tutorials, and tools to help others learn, build, and grow. From software development to everyday tech challenges, if it helps someone level up, it’s worth writing about