Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"

# ANSI colors
RED="\033[0;31m"
YELLOW="\033[0;33m"
CYAN="\033[0;36m"
GREEN="\033[0;32m"
RESET="\033[0m"

commit_msg_file=$1

# Guard: ensure commit message file exists
Expand All @@ -11,7 +18,7 @@ if [ -z "$commit_msg_file" ] || [ ! -f "$commit_msg_file" ]; then
fi

if ! grep -q "Signed-off-by:" "$commit_msg_file"; then
echo "Commit message missing Signed-off-by line"
echo "Use: git commit -s ..."
echo "${RED} Commit message missing Signed-off-by line ${RESET}"
echo "${GREEN} Use: git commit -s ... ${RESET}"
exit 1
fi
63 changes: 58 additions & 5 deletions .husky/pre-push
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
#!/bin/bash

# . "$(dirname -- "$0")/_/husky.sh"

# ANSI colors
RED="\033[0;31m"
Expand All @@ -10,16 +11,66 @@ RESET="\033[0m"

echo "🔒 Checking commit signatures..."

# Read stdin into a temp file
TMP_FILE=$(mktemp)
cat > "$TMP_FILE"

if [ ! -s "$TMP_FILE" ]; then
echo "⚠️ Validations won't apply when current branch and remote branch being pushed to are different."
fi
Comment on lines +18 to +20
Copy link

@coderabbitai coderabbitai bot Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Clarify the warning message to accurately reflect the condition.

The warning message states "Validations won't apply when current branch and remote branch being pushed to are different," but it's triggered when stdin is empty, which can occur in various scenarios beyond just differing branches (e.g., nothing to push, certain git operations).

Consider revising to:

-  echo "⚠️ Validations won't apply when current branch and remote branch being pushed to are different."
+  echo "⚠️ No refs to push - skipping commit signature validation."
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [ ! -s "$TMP_FILE" ]; then
echo "⚠️ Validations won't apply when current branch and remote branch being pushed to are different."
fi
if [ ! -s "$TMP_FILE" ]; then
echo "⚠️ No refs to push - skipping commit signature validation."
fi
🤖 Prompt for AI Agents
In .husky/pre-push around lines 18 to 20, the warning text incorrectly ties the
condition to differing branches while the check actually detects an empty stdin
(no ref info), which can happen for reasons like nothing to push or certain git
operations; update the message to accurately state that no ref info was received
(stdin is empty) and therefore pre-push validations may be skipped, and
optionally include brief examples (e.g., nothing to push, special git workflows)
to make the warning clear.

Copy link
Contributor Author

@sujitaw sujitaw Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@coderabbitai when pushing to other remote branches for eg : my current local branch is develop and i perform git push origin main in that scenario too the refs are empty .
is there any other way to address this scenario

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Research git pre-push hook documentation and behavior
# Check if there are any environment variables or other ways to detect the scenario

# First, let's check what information is typically available in a pre-push hook
echo "=== Git pre-push hook documentation ==="
git help hooks 2>/dev/null | grep -A 30 "pre-push" | head -40

echo ""
echo "=== Checking git environment variables that might help ==="
# List common git environment variables that might be available
cat << 'EOF'
Common Git environment variables that might be available in pre-push hook:
- GIT_DIR
- GIT_WORK_TREE
- GIT_INDEX_FILE
- GIT_PREFIX
- GIT_REFLOG_ACTION
- GIT_PUSH_OPTION_COUNT
- GIT_PUSH_OPTION_<n>

Note: The pre-push hook receives information via stdin, not command-line arguments.
EOF

echo ""
echo "=== Understanding when stdin is empty ==="
cat << 'EOF'
The pre-push hook receives on stdin (one line per ref being pushed):
<local ref> <local sha1> <remote ref> <remote sha1>

stdin is empty when:
1. Nothing to push (local ref is already up-to-date with remote)
2. Specified ref doesn't exist locally
3. Push is a dry-run or gets rejected before refs are determined

For 'git push origin main' from 'develop' branch:
- If local 'main' exists and differs from 'origin/main': stdin will have data
- If local 'main' doesn't exist: error before hook runs
- If local 'main' is up-to-date with 'origin/main': stdin will be empty (nothing to push)
EOF

Length of output: 1030


🌐 Web query:

git pre-push hook empty stdin scenarios

💡 Result:

Short answer — pre-push hook stdin will be empty when there are no refs/objects being sent, or when something else has already consumed/failed to forward that input.

Common scenarios

  • Nothing to push (git finds no changed refs) — git will not write any lines to the hook’s stdin. [1]
  • Your hook/script (or a helper it calls, e.g. git-lfs) reads stdin before your read-loop, so subsequent reads see EOF. Move the read-loop before anything that consumes stdin. [2]
  • A wrapper/tool running the hook (some hook managers) doesn’t forward git’s stdin into the actual hook process, so the hook sees empty stdin. Check the wrapper’s implementation/config. [3]

What to do

  • Write your hook to handle empty stdin gracefully (e.g., use while read ...; do …; done and treat zero iterations as “nothing to check”). [1]
  • Ensure no commands run before the read-loop that might consume stdin. [2]
  • If using a hook manager/wrapper, verify it forwards stdin or run the hook directly. [3]

Sources
[1] Stack Overflow: “Git-hooks pre-push script does not receive input via STDIN”.
[2] Stack Overflow: “git pre-push hook stdin is empty” (notes about git-lfs and ordering).
[3] GitHub issue / wrapper discussion (lefthook) and Git hooks docs about pre-push input handling.


@sujitaw, great question! Let me explain what's happening in your scenario.

Why stdin is empty

When you run git push origin main from your develop branch:

  • Git compares your local main branch with origin/main
  • If they're identical (nothing new to push), Git doesn't send any ref information to the pre-push hook
  • This results in empty stdin

The pre-push hook only receives stdin with ref information when there are actual commits/refs to push. It doesn't receive the command-line arguments (like which branch you specified), so it can't distinguish between:

  • "Nothing to push because refs are up-to-date"
  • "Pushing a different branch than current HEAD"
  • Other scenarios that result in empty stdin

Current behavior is correct

The current code handles this appropriately:

  1. Detects empty stdin
  2. Shows a warning
  3. Continues without blocking (which is correct - you shouldn't block a no-op push)
  4. Skips validation since there are no commits to validate

Suggested improvement

The only thing we can improve is making the warning message more accurate and informative:

if [ ! -s "$TMP_FILE" ]; then
  echo "⚠️  No refs to push - skipping commit signature validation."
  echo "    (This occurs when local and remote refs are already in sync)"
fi

This message is more accurate because:

  • It correctly states why validation is skipped (no refs to push)
  • It doesn't make assumptions about branch differences
  • It provides context about what "no refs" means

Bottom line: There's no programmatic way in the pre-push hook to detect your specific scenario differently from other empty-stdin cases, but that's okay—the hook should skip validation when there's nothing to push, regardless of the reason. The improved warning message makes this clearer to users.


🧠 Learnings used
Learnt from: GHkrishna
Repo: credebl/platform PR: 1469
File: .husky/pre-push:34-35
Timestamp: 2025-09-30T06:35:15.488Z
Learning: In the credebl/platform repository's pre-push hook (.husky/pre-push), when checking commit signatures, user GHkrishna encountered an edge case where pulling squashed commits from other contributors causes signature validation issues because those commits are signed with others' GPG keys. The user prefers a solution that distinguishes local commits from upstream commits to apply signature validation only to the current user's own commits.

Learnt from: GHkrishna
Repo: credebl/platform PR: 1468
File: .husky/pre-push:47-56
Timestamp: 2025-09-29T12:14:52.484Z
Learning: User GHkrishna prefers allowing automatic rebase in pre-push hooks for signing commits, considering it acceptable since they're rebasing their own local commits before sharing.


while read local_ref local_sha remote_ref remote_sha; do
# Determine range of commits
if [ "$remote_sha" = "0000000000000000000000000000000000000000" ]; then
range="$local_sha"
# Use the branch being pushed (may differ from HEAD)
if echo "$local_ref" | grep -q '^refs/heads/'; then
target_branch=${local_ref#refs/heads/}
else
target_branch=$(git rev-parse --abbrev-ref HEAD)
fi

# Find closest local base branch by commit distance (exclude the target itself)
base_branch=$(
git for-each-ref --format='%(refname:short)' refs/heads/ \
| grep -vxF "$target_branch" \
| while IFS= read -r other_branch; do
merge_base=$(git merge-base "$target_branch" "$other_branch") || continue
[ -n "$merge_base" ] || continue
echo "$(git rev-list --count "${merge_base}..${target_branch}") $other_branch"
done \
| sort -n \
| head -n1 \
| awk '{print $2}'
)

if [ -z "$base_branch" ]; then
# Resolve remote default (origin/HEAD) or use $default_branch/main
base_branch=${default_branch:-$(git symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's@^origin/@@')}
[ -n "$base_branch" ] || base_branch=main
echo "⚠️ Base branch not found — defaulting to '${base_branch}'"
fi

# Prefer local base, else remote tracking
if git show-ref --verify --quiet "refs/heads/$base_branch"; then
base_ref="$base_branch"
else
base_ref="origin/$base_branch"
fi

base_commit=$(git merge-base "$base_ref" "$target_branch" 2>/dev/null || true)
if [ -n "$base_commit" ]; then
range="$base_commit..$local_sha"
else
# Safe minimal fallback: just the tip commit
range="$local_sha"
fi
else
range="$remote_sha..$local_sha"
fi

unsigned_commits=""

echo "commit range ${range}"
# Loop through each commit in range
for commit in $(git rev-list $range); do
# Skip merge commits
Expand Down Expand Up @@ -86,6 +137,8 @@ while read local_ref local_sha remote_ref remote_sha; do
exit 1
fi
fi
done
done < "$TMP_FILE"

rm -f "$TMP_FILE"

echo "${GREEN}✅ No unsigned commits found${RESET}"
echo "${GREEN}✅ No unsigned commits found${RESET}"