Source Code Control for Business Apps: Git Tips to Avoid Costly Bugs
The bug that sticks with me wasn’t fancy. No hacker movie stuff. It was an invoice total that sometimes… just sometimes… doubled.
A customer rang up, annoyed but polite in that very specific way that means they’ve already lost an hour of their day. “Your app charged us twice,” they said. And I did the classic developer thing—half denial, half panic. “It can’t,” I said, while my stomach quietly disagreed.
It turned out to be a merge problem. Two changes, made days apart, collided in exactly the wrong place. We’d been emailing ZIP files of the code around like it was 2004. No proper source-code control. No clear history. No easy way to see what changed and when.
If you’re building a business app—or trying to improve one you already rely on—source code control is one of those boring-sounding things that saves you from expensive, reputation-denting nonsense. Git is the common choice. GitHub (or GitLab, or Bitbucket) is where it usually lives. And yes, it can feel like learning to drive with a manual gearbox while someone yells directions. But it’s worth it.
What source code control actually does (when it’s done properly)
Source code control is a system for tracking changes to your app’s code over time. That’s the textbook line. The real-world version is simpler: it gives you a memory.
Not your memory—because yours is busy remembering client meetings, passwords, and whether you replied to that email. The project’s memory. What changed. Who changed it. Why it changed. And how to undo it when it turns out to be a terrible idea.
Git is the tool most teams use. It’s not the only one, but it’s the one you’ll bump into everywhere. GitHub is the popular hosting platform, and it adds the practical bits—pull requests, reviews, issue tracking, and a place for your code to live that isn’t someone’s laptop held together with hope.
And if you’re thinking, “We’re a small business, we don’t need that”—I get it. But small teams are exactly the ones who get hurt by messy code changes, because you don’t have spare people to firefight.
One main branch. One way to ship. No mystery
If you take only one thing from this, make it this: decide how code becomes the version your business app runs on. Then write it down somewhere obvious.
I’ve seen “main”, “master”, “production”, “live-final”, and my personal favourite, “main2”. The name isn’t the point. The point is that everyone knows which branch is the source of truth.
A simple setup works for most business apps:
- main (or master): what’s in production, or what you’re about to deploy
- develop (optional): where features collect before release
- feature branches: one branch per change, short-lived
If your app is small, you can even skip “develop” and just do feature branches into “main”. Fewer moving parts. Less ceremony. More clarity.
The costly bugs love ambiguity. Git doesn’t remove risk—but it makes the risk visible.
Branch like you mean it (small, focused, and short-lived)
A feature branch should be boring. That’s the goal. You create it, you make a small change, you merge it, you delete it. Done.
Where people get into trouble is letting branches live for weeks. The longer a branch hangs around, the more the rest of the codebase moves on without it. Then you merge and get conflicts, surprise behaviour, and that weird feeling that the app is haunted.
If you’re building a business app, keep branches tied to business-shaped chunks:
- “Add VAT number to invoice screen”
- “Fix rounding bug in totals”
- “Send receipt email after payment”
Not “Invoice overhaul v3”. That’s how you end up merging a novel instead of a chapter.
Small branches also mean you can roll back a change without rolling back half your month.
Commit messages that future-you won’t hate
Most commit messages are either lies (“fix stuff”) or poetry (“final final fix”). Mine included. No judgement.
But good commit messages are like good labels on cables. You don’t appreciate them until something breaks and you’re crawling under the desk with a torch.
Try this pattern:
- What you changed, in plain language
- Why you changed it (especially if it’s not obvious)
Examples that have saved my skin:
- Fix invoice total rounding when discount applied
- Prevent duplicate charge by making payment callback idempotent
- Add validation for empty customer email to stop failed sends
Notice how none of that is “refactor”. Refactor is fine, but say what you refactored and why. Your future teammate might be you, six months older and significantly less patient.
Pull requests: the cheapest bug filter you’ll ever buy
GitHub pull requests (or merge requests in GitLab) sound formal. They don’t have to be. Think of them as a pause before you change the thing your business relies on.
Even if you’re a solo developer, opening a pull request helps. It forces you to explain what you did. It gives you a clean view of the changes. And it creates a natural point to run tests before you merge.
If you have even one other person who can review, use them. Not to criticise your code style. To catch the obvious stuff you can’t see because you’ve been staring at it for three hours.
A decent pull request description is simple:
- What problem it solves
- How you tested it (even if it’s “clicked around for 10 minutes”)
- Any risk or edge cases
I’ve watched a two-minute review prevent a two-day rollback. That’s a very good trade.
Tag releases like you’ll need to explain them in court
When something goes wrong in production, the first question is always: “What changed?” The second is: “When did it change?”
Git tags help you answer both without guessing. Tag the code that goes out the door. Give it a version number or a date-based label. Something you can point to.
For business apps, I like simple:
- v1.8.0 for a planned release
- v1.8.1 for a quick patch
Then, when someone says, “This started happening last Tuesday,” you can check what was deployed. Not what you think was deployed. What actually was.
And yes, I’ve been the person who thought they deployed one thing and accidentally deployed another. Git didn’t stop me being human, but it did make the truth easy to find.
Use Git to make rollbacks boring
A rollback shouldn’t be a dramatic event with late-night messages and pizza boxes. It should be a slightly annoying button press.
If you deploy from a tagged release, rolling back is just redeploying the previous tag. If you deploy from “main”, rolling back might mean reverting a merge commit. Either way, Git makes it possible to go backwards cleanly.
The trick is practising the “go backwards” path before you need it. Not in a big rehearsal. Just once in a while, make sure you know how your team would undo a change without making the situation worse.
Because the worst bugs aren’t the ones that exist. They’re the ones you can’t escape.
.gitignore, secrets, and other quiet disasters
Let’s talk about the mistake everyone makes once. You accidentally commit a secret. An API key. A database password. Something that absolutely should not live in GitHub.
Source code control remembers everything. That’s its job. Which means “I deleted it” doesn’t really mean deleted.
Do the boring prevention:
- Use a solid .gitignore so you don’t commit build files, logs, or local settings
- Store secrets in environment variables or a secrets manager, not in code
- Use GitHub’s secret scanning if you can
If you do commit a secret, rotate it immediately. Don’t negotiate with yourself. Assume it’s compromised and move on.
I wish I could say I learned that from a blog post. I did not.
Make Git fit the business, not the other way round
Here’s the part people miss: source code control isn’t just for developers. It’s for the business.
When you have clean Git habits, you can answer business questions quickly:
- “Can we ship this fix today without shipping the unfinished feature?”
- “What changed between last month and now?”
- “If we try this idea and it flops, can we undo it?”
Git gives you options. Options reduce panic. Panic is expensive.
And if you’re hiring someone to build your app, ask them how they use Git. Not in a gotcha way. Just curiosity. If the answer is “I email you the latest files,” you’ve learned something important—maybe too important.
A healthy Git workflow doesn’t have to be fancy. It just has to be consistent. A main branch that means something. Small branches. Decent commit messages. Pull requests. Tagged releases. The ability to roll back without prayer.
Because most costly bugs aren’t born from incompetence. They’re born from confusion—two people making reasonable changes in a system that doesn’t keep its story straight.
Git, for all its quirks, is a way of keeping the story straight. And when your app is how you get paid… that’s not a bad thing to be fussy about.
I still get that little jolt of dread when a production issue comes in. I don’t think that ever goes away. But with source code control done well, the dread doesn’t turn into chaos. It turns into a process. And then, eventually, into a fix.
