Z40 = '0' * 40 hardcoding breaks `git push --delete` on SHA-256 repos · Issue #3664 · pre-commit/pre-commit · GitHub
Skip to content

Z40 = '0' * 40 hardcoding breaks git push --delete on SHA-256 repos #3664

@rlichtenwalter

Description

@rlichtenwalter

search you tried in the issue tracker

sha256, SHA-256 push, sha-256 delete, Z40, object-format sha256, "Invalid revision range", "bad object", zero SHA, pre-push delete, deletion push

The closest related hit is #3434 (closed), but that is about fetching sha1-format hook repos into a sha256 local repo — a different codepath.

describe your issue

pre_commit/commands/hook_impl.py hardcodes the SHA-1 zero OID:

Z40 = '0' * 40

It is compared against local_sha / remote_sha to detect deletion-only pushes and new branches:

if local_sha == Z40:
    continue
elif remote_sha != Z40 and _rev_exists(remote_sha):
    ...

In a repository initialized with --object-format=sha256, git's pre-push hook protocol emits 64-character zero OIDs rather than 40. The equality never matches, the deletion-only short-circuit never fires, and pre-commit falls through into git diff --name-only ... <old>..<64-zeros> (and then <old>...<64-zeros>). Both error out:

fatal: Invalid revision range 3dac4c61...6dce8d..000000...(×64)
fatal: Invalid symmetric difference expression 3dac4c61...6dce8d...000000...(×64)

pre-commit surfaces these as An unexpected error has occurred: CalledProcessError and exits non-zero, so git push origin --delete <branch> is refused on every sha256 repo. Branch deletion has to go through the forge's web UI or API to succeed.

Minimal reproducer:

git init --object-format=sha256 repro
cd repro
git config user.email t@e.com && git config user.name T
git commit --allow-empty -m init
cat > .pre-commit-config.yaml <<'EOF'
repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: trailing-whitespace
EOF
git add .pre-commit-config.yaml && git commit -m "pc"
pre-commit install --hook-type pre-push

git checkout -b doomed
git commit --allow-empty -m x
SHA=$(git rev-parse HEAD)
ZEROS=$(printf '0%.0s' $(seq 1 64))

# Feed git's pre-push stdin format directly — simulates `git push origin --delete doomed`
printf '(delete) %s refs/heads/doomed %s\n' "$ZEROS" "$SHA" | .git/hooks/pre-push origin .
# exit code 3, error above

Suggested fix: accept an all-zero OID of either supported length (40 or 64), or (more general) read the repo's zero OID at runtime. A one-liner that covers both currently-supported object formats:

def _is_zero_oid(oid: str) -> bool:
    return len(oid) in (40, 64) and set(oid) == {'0'}

Callers become if _is_zero_oid(local_sha): continue and elif not _is_zero_oid(remote_sha) and _rev_exists(remote_sha):. A strictly hash-agnostic alternative reads git rev-parse --show-object-format once per hook invocation and computes the zero string from it.

Happy to open a PR if helpful.

pre-commit --version

pre-commit 4.5.1 (reproduced); Z40 = '0' * 40 is still on line 14 of hook_impl.py on current main (f35134b) and in the 4.6.0 tag, so the bug is present on both.

.pre-commit-config.yaml

repos:
  - repo: https://github.com/pre-commit/pre-commit-hooks
    rev: v5.0.0
    hooks:
      - id: trailing-whitespace

~/.cache/pre-commit/pre-commit.log (if present)

### version information

pre-commit version: 4.5.1
git --version: git version 2.47.3
sys.version:
    3.12.12 (main, Jan 16 2026, 00:00:00) [GCC 14.3.1 20250617 (Red Hat 14.3.1-2)]
sys.executable: /home/rlichten/.local/share/uv/tools/pre-commit/bin/python
os.name: posix
sys.platform: linux

### error information

An unexpected error has occurred: CalledProcessError: command: ('/usr/bin/git', 'diff', '--name-only', '--no-ext-diff', '-z', '<sha>..<64-zeros>')
return code: 128
stdout: (none)
stderr:
    fatal: Invalid revision range <sha>..<64-zeros>

Traceback (most recent call last):
  File ".../pre_commit/git.py", line 161, in get_changed_files
    _, out, _ = cmd_output(*diff_cmd, f'{old}...{new}')
  ...
pre_commit.util.CalledProcessError: command: ('/usr/bin/git', 'diff', '--name-only', '--no-ext-diff', '-z', '<sha>...<64-zeros>')
return code: 128
stderr:
    fatal: Invalid symmetric difference expression <sha>...<64-zeros>

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions