The accident
On monday, I pushed code directly to main without creating a feature branch. This could have resulted in an unintentional deployment to staging. Fortunately, it was only an update to .gitignore! ;)
The context
In my current project, developers with the “maintainer” role can push directly to main. This is new to me, but intentional - the team trusts its maintainers. While that trust is great, I’ve developed a few habits that, while usually harmless, led to this accident:
- Diving straight into the code: When I’m focused on solving a problem, I sometimes forget to create a feature branch immediately. This means I’m working without some “safe” guardrails from the start.
- The “Commit and Push” reflex: Pushing code immediately after a commit is generally a good habit, but in this specific environment, it can lead to trouble.
The sudden freedom to push to main caught me off guard. I was used to restricted permissions where git push would simply return an error if I tried to hit the primary branch.
The solution
The fix for the future is simple: a pre-push Git hook. It requires setting a specific environment variable before allowing a push to main.
Nothing fancy—just a basic check—but it’s enough to prevent unintended pushes without forcing me to radically change my workflow. Most importantly, it still allows me to bypass the hook if a direct push is actually necessary.
I have it at ~/.git/hooks/pre-push and it looks like this:
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/sh
protected_branches="main master"
while read local_ref local_sha remote_ref remote_sha; do
branch=$(git rev-parse --symbolic --abbrev-ref "$remote_ref")
for protected in $protected_branches; do
if [ "$branch" = "$protected" ] && [ "$PUSH_TO_PROTECTED" != "1" ]; then
echo "Set PUSH_TO_PROTECTED=1 to push to $protected."
exit 1
fi
done
done
exit 0