#!/bin/sh # # Pre-push hook: catch stray uncommitted work and doomed non-fast-forward pushes # BEFORE contacting the remote, with clearer messages than git's own errors. # # History: an earlier version of this hook also *blocked* whenever local commits # existed that weren't on origin (an "unpushed commits" check). That is # self-defeating — having commits to push is what a push IS — so it rejected # every meaningful push and forced --no-verify. Removed 2026-07-11. The useful # intent behind it (spot surprise commits from other sessions/tools sharing this # branch) is now served by the informational listing below, which never blocks. # set -e echo "--- pre-push: checking for uncommitted changes ---" if ! git diff --quiet --exit-code; then echo "⚠️ WARNING: You have uncommitted working-tree changes." echo " These may be VS Code auto-saves or edits you forgot to stage." echo " Run 'git diff' to review, then commit or stash before pushing." echo "" echo " To push anyway, run: git push --no-verify" exit 1 fi if ! git diff --cached --quiet --exit-code; then echo "⚠️ WARNING: You have staged but uncommitted changes." echo " These may be VS Code auto-stages or partial commits." echo " Run 'git diff --cached' to review, then commit before pushing." echo "" echo " To push anyway, run: git push --no-verify" exit 1 fi BRANCH=$(git rev-parse --abbrev-ref HEAD) REMOTE="origin/$BRANCH" if git rev-parse --verify "$REMOTE" >/dev/null 2>&1; then # Fail fast (with clear advice) if the remote-tracking ref already has commits # we lack — the push would be rejected as non-fast-forward anyway. This catches # the "another session pushed first" race with a better message than git's. # (Based on the last fetch; a race newer than that is still caught by git itself.) BEHIND=$(git rev-list --count "$BRANCH..$REMOTE" 2>/dev/null || echo 0) if [ "$BEHIND" -gt 0 ]; then echo "⚠️ BLOCKED: $REMOTE has $BEHIND commit(s) you don't have — this push would be rejected." echo " Another session/tool likely pushed first (as of your last fetch)." echo " Run: git pull --rebase then push again." exit 1 fi # Informational only — never blocks: show exactly what this push will publish, # so commits made by other sessions/tools on this branch get noticed. AHEAD=$(git rev-list --count "$REMOTE..$BRANCH" 2>/dev/null || echo 0) if [ "$AHEAD" -gt 0 ]; then echo "--- pre-push: publishing $AHEAD commit(s): ---" git log --oneline "$REMOTE..$BRANCH" | sed 's/^/ /' fi fi echo "--- pre-push: all checks passed ---"