Skip to content

fix: skip pre-push checks on branch deletion#1004

Merged
affaan-m merged 1 commit into
affaan-m:mainfrom
ohashi-mizuki:fix/pre-push-skip-branch-deletion
Mar 30, 2026
Merged

fix: skip pre-push checks on branch deletion#1004
affaan-m merged 1 commit into
affaan-m:mainfrom
ohashi-mizuki:fix/pre-push-skip-branch-deletion

Conversation

@ohashi-mizuki

@ohashi-mizuki ohashi-mizuki commented Mar 29, 2026

Copy link
Copy Markdown

Summary

  • Fix pre-push hook blocking git push origin --delete <branch> operations
  • Detect deletion pushes by reading stdin (local sha is all zeros for deletes) and exit early
  • No behavior change for normal code pushes

Problem

The pre-push hook runs lint/typecheck/test/build checks on every push, including branch deletions (git push origin --delete <branch>). Since branch deletion does not push any code, running verification checks is unnecessary and blocks the operation, forcing users to use workarounds like gh api to delete remote branches.

Solution

Read the pre-push hook's stdin to detect deletion pushes. Git provides push info in the format <local ref> <local sha> <remote ref> <remote sha>. For deletions, the local sha is the zero OID (0000000000000000000000000000000000000000). When all pushed refs are deletions, skip checks and exit early.

Test plan

  • git push origin --delete <branch> completes without running checks
  • Normal git push still runs lint/typecheck/test/build as expected
  • git push origin <branch> --delete <other-branch> (mixed) still runs checks

🤖 Generated with Claude Code


Summary by cubic

Skip pre-push checks when deleting remote branches to unblock git push origin --delete <branch>. Normal and mixed pushes still run checks.

  • Bug Fixes
    • Parse pre-push stdin; if all local SHAs are zero OIDs, exit before running checks.
    • If any ref has a real SHA, run lint/typecheck/test/build as before.

Written for commit 0c166e1. Summary will update on new commits.

Summary by CodeRabbit

  • Chores
    • Enhanced pre-push hook to detect deletion-only pushes and skip verification checks for such operations, improving the speed of branch deletion workflows. Non-deletion pushes continue with existing lint, type-check, test, build, and audit verification checks for Node projects; Go test for Go projects; and pytest for Python projects.

The pre-push hook runs lint/typecheck/test/build checks on every push,
including `git push origin --delete <branch>`. Branch deletion does not
push any code, so verification checks are unnecessary and block the
delete operation.

Detect deletion pushes by reading stdin (local sha is all zeros for
deletes) and exit early.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Mar 29, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

The pre-push git hook now detects deletion-only pushes by examining stdin ref updates. When all updates indicate deletions (local SHA is zero), the hook exits early with success, bypassing lint, test, and build checks. Non-deletion pushes proceed with existing verification flows.

Changes

Cohort / File(s) Summary
Pre-push Hook Enhancement
scripts/codex-git-hooks/pre-push
Added deletion-only detection logic at hook start. Reads pre-push stdin ref updates and immediately exits with success if all updates are deletions (zero local SHA). Otherwise, continues with existing Node, Go, and Python verification checks.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 Hops and deletes with glee,
No tests needed when refs shall be free,
Zero SHA marks the path of release,
Early exit brings the hook sweet peace!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main change: skipping pre-push checks during branch deletion operations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps

greptile-apps Bot commented Mar 29, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes the pre-push hook to skip lint/typecheck/test/build checks when the push is a branch deletion by reading Git's stdin (<local ref> <local sha> <remote ref> <remote sha>) and exiting early if all local SHAs are the zero OID. The approach is idiomatic and aligns with Git's documented hook protocol.

Key changes:

  • Reads pre-push stdin to classify each ref as a deletion (local sha == zero OID) or a normal push
  • Introduces is_delete_only flag; exits 0 (skips checks) only when every ref in the push is a deletion
  • Mixed pushes (some deletions, some normal refs) continue to run all checks as documented in the test plan

Issues found:

  • The zero OID is hardcoded as 40 hex zeros, which is only correct for SHA-1 repos. SHA-256 repos use a 64-character zero OID and will not match, causing deletions to still run all checks.
  • is_delete_only is initialised to true before the loop. If stdin produces zero lines (empty input from a GUI, CI harness, or wrapper that doesn't plumb stdin correctly), the flag stays true and the hook exits 0, silently skipping every check on an otherwise normal push.

Confidence Score: 4/5

Safe to merge after addressing the empty-stdin bypass, which can silently skip all push checks on non-git invocations.

The core logic is correct for the normal git use-case. However, the is_delete_only=true default means that any invocation where stdin is not supplied (CI harness, GUI client, manual call) will exit 0 and skip all checks — a present defect on the changed path that deserves a fix before merging. The SHA-256 zero-OID mismatch is an additional correctness issue for that object-format. Both are straightforward to fix.

scripts/codex-git-hooks/pre-push — review the zero-OID constant and the empty-stdin default.

Important Files Changed

Filename Overview
scripts/codex-git-hooks/pre-push Adds stdin-based deletion detection before running verification checks; correct for the common SHA-1 case but the zero-OID check is hardcoded to 40 chars (misses SHA-256 repos), and the is_delete_only=true default silently skips all checks when stdin is empty.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[git push triggered] --> B{ECC_SKIP_GIT_HOOKS\nor ECC_SKIP_PREPUSH set?}
    B -- yes --> Z[exit 0 — skip all checks]
    B -- no --> C{.ecc-hooks-disable\nfile present?}
    C -- yes --> Z
    C -- no --> D{Inside a git\nwork tree?}
    D -- no --> Z
    D -- yes --> E[Read stdin lines:\nlocal_ref local_sha remote_ref remote_sha]
    E --> F{local_sha == zero OID\nfor ALL refs?}
    F -- yes: deletion-only push --> Z
    F -- no: at least one normal ref --> G[Run verification checks:\nlint · typecheck · test · build]
    G --> H{Any check\nfailed?}
    H -- yes --> X[exit 1 — block push]
    H -- no --> Y[exit 0 — allow push]

    style Z fill:#d4edda,stroke:#28a745
    style X fill:#f8d7da,stroke:#dc3545
    style Y fill:#d4edda,stroke:#28a745
Loading

Reviews (1): Last reviewed commit: "fix: skip pre-push checks on branch dele..." | Re-trigger Greptile

Comment on lines +22 to +30
is_delete_only=true
while read -r _local_ref local_sha _remote_ref _remote_sha; do
if [[ "$local_sha" != "0000000000000000000000000000000000000000" ]]; then
is_delete_only=false
break
fi
done
if [[ "$is_delete_only" == "true" ]]; then
exit 0

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Zero OID length mismatch for SHA-256 repositories

The hardcoded zero OID (0000... with 40 hex chars) only matches SHA-1 object names. Repositories initialized with git init --object-format=sha256 use a 64-character zero OID, so this check will never match and branch deletions will incorrectly run all verification checks.

A more robust approach is to test whether the sha is all-zero characters of any length using a regex:

Suggested change
is_delete_only=true
while read -r _local_ref local_sha _remote_ref _remote_sha; do
if [[ "$local_sha" != "0000000000000000000000000000000000000000" ]]; then
is_delete_only=false
break
fi
done
if [[ "$is_delete_only" == "true" ]]; then
exit 0
is_delete_only=true
while read -r _local_ref local_sha _remote_ref _remote_sha; do
if [[ "$local_sha" =~ ^0+$ ]]; then
: # deletion ref, continue
else
is_delete_only=false
break
fi
done
if [[ "$is_delete_only" == "true" ]]; then
exit 0
fi

This handles both SHA-1 (40 zeros) and SHA-256 (64 zeros) repositories.

Comment on lines +22 to +31
is_delete_only=true
while read -r _local_ref local_sha _remote_ref _remote_sha; do
if [[ "$local_sha" != "0000000000000000000000000000000000000000" ]]; then
is_delete_only=false
break
fi
done
if [[ "$is_delete_only" == "true" ]]; then
exit 0
fi

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Empty stdin causes all checks to be silently skipped

is_delete_only is initialized to true before the while read loop. If stdin is empty (no lines are produced), the loop body never executes and the flag stays true, causing the hook to exit 0 and skip every verification check on the push.

While git's spec says the pre-push hook is only called when at least one ref is being pushed, there are real-world edge cases where stdin can be empty:

  • Hook invoked manually or via a CI harness that doesn't supply stdin
  • Certain git GUI clients or wrappers that call the hook without piping stdin correctly
  • Future git behaviour changes

The fix is to guard against the empty-stdin case by tracking whether any line was actually read:

Suggested change
is_delete_only=true
while read -r _local_ref local_sha _remote_ref _remote_sha; do
if [[ "$local_sha" != "0000000000000000000000000000000000000000" ]]; then
is_delete_only=false
break
fi
done
if [[ "$is_delete_only" == "true" ]]; then
exit 0
fi
is_delete_only=true
got_any_ref=false
while read -r _local_ref local_sha _remote_ref _remote_sha; do
got_any_ref=true
if [[ "$local_sha" != "0000000000000000000000000000000000000000" ]]; then
is_delete_only=false
break
fi
done
if [[ "$got_any_ref" == "true" && "$is_delete_only" == "true" ]]; then
exit 0
fi

This ensures the early-exit path is only taken when git actually reported deletion refs, not when stdin happened to be empty.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
scripts/codex-git-hooks/pre-push (1)

19-31: Logic is correct; consider guarding against empty stdin.

The deletion detection correctly identifies pushes where all refs have the zero OID. However, if stdin is unexpectedly empty (e.g., the wrapper fails to pipe input), is_delete_only remains true and all verification checks are silently skipped.

This is unlikely in normal git operations, but adding a guard ensures checks only skip when deletion refs are actually present.

🛡️ Suggested defensive improvement
 is_delete_only=true
+has_refs=false
 while read -r _local_ref local_sha _remote_ref _remote_sha; do
+  has_refs=true
   if [[ "$local_sha" != "0000000000000000000000000000000000000000" ]]; then
     is_delete_only=false
     break
   fi
 done
-if [[ "$is_delete_only" == "true" ]]; then
+if [[ "$has_refs" == "true" && "$is_delete_only" == "true" ]]; then
   exit 0
 fi
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/codex-git-hooks/pre-push` around lines 19 - 31, The current
deletion-detection loop using is_delete_only and the while read -r _local_ref
local_sha _remote_ref _remote_sha may exit early when stdin is empty and
incorrectly treat the push as a delete; to fix this, add a guard that tracks
whether any refs were actually read (e.g., set a read_any flag inside the loop
when it iterates) and only treat is_delete_only as authoritative if read_any is
true; implement by initializing read_any=false before the while, set
read_any=true inside the loop, and change the final condition to exit 0 only
when is_delete_only == "true" AND read_any == "true".
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@scripts/codex-git-hooks/pre-push`:
- Around line 19-31: The current deletion-detection loop using is_delete_only
and the while read -r _local_ref local_sha _remote_ref _remote_sha may exit
early when stdin is empty and incorrectly treat the push as a delete; to fix
this, add a guard that tracks whether any refs were actually read (e.g., set a
read_any flag inside the loop when it iterates) and only treat is_delete_only as
authoritative if read_any is true; implement by initializing read_any=false
before the while, set read_any=true inside the loop, and change the final
condition to exit 0 only when is_delete_only == "true" AND read_any == "true".

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9ff88f72-8975-4f38-b54e-fd510e6ef335

📥 Commits

Reviewing files that changed from the base of the PR and between 527c793 and 0c166e1.

📒 Files selected for processing (1)
  • scripts/codex-git-hooks/pre-push

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

1 issue found across 1 file

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/codex-git-hooks/pre-push">

<violation number="1" location="scripts/codex-git-hooks/pre-push:24">
P2: Delete-only detection is SHA-1-specific due to hardcoded 40-zero OID and can fail in non-SHA-1 repositories.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

# For deletions, the local sha is the zero OID.
is_delete_only=true
while read -r _local_ref local_sha _remote_ref _remote_sha; do
if [[ "$local_sha" != "0000000000000000000000000000000000000000" ]]; then

@cubic-dev-ai cubic-dev-ai Bot Mar 29, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2: Delete-only detection is SHA-1-specific due to hardcoded 40-zero OID and can fail in non-SHA-1 repositories.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/codex-git-hooks/pre-push, line 24:

<comment>Delete-only detection is SHA-1-specific due to hardcoded 40-zero OID and can fail in non-SHA-1 repositories.</comment>

<file context>
@@ -16,6 +16,20 @@ if ! git rev-parse --is-inside-work-tree >/dev/null 2>&1; then
+# For deletions, the local sha is the zero OID.
+is_delete_only=true
+while read -r _local_ref local_sha _remote_ref _remote_sha; do
+  if [[ "$local_sha" != "0000000000000000000000000000000000000000" ]]; then
+    is_delete_only=false
+    break
</file context>
Suggested change
if [[ "$local_sha" != "0000000000000000000000000000000000000000" ]]; then
if [[ ! "$local_sha" =~ ^0+$ ]]; then
Fix with Cubic

@affaan-m affaan-m merged commit db12d3d into affaan-m:main Mar 30, 2026
4 checks passed
peiking88 pushed a commit to peiking88/everything-claude-code that referenced this pull request Apr 4, 2026
…-branch-deletion

fix: skip pre-push checks on branch deletion
FrancescoRosciano pushed a commit to FRosciano-Mambo/everything-claude-code that referenced this pull request Jun 1, 2026
…-branch-deletion

fix: skip pre-push checks on branch deletion
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants