Skip to content
Merged
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
60 changes: 33 additions & 27 deletions .githooks/README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,63 @@
# Git Hooks

This directory contains Git hooks for the ExecuTorch repository.
This directory contains Git hooks for the ExecuTorch repository. It is used as
`core.hooksPath`, so git looks here instead of `.git/hooks/`.

## Pre-commit Hook
## Hooks

The pre-commit hook automatically updates the PyTorch commit pin in `.ci/docker/ci_commit_pins/pytorch.txt` whenever `torch_pin.py` is modified.
### pre-commit

### How It Works
Runs on every commit:

1. When you commit changes to `torch_pin.py`, the hook detects the change
2. It parses the `NIGHTLY_VERSION` field (e.g., `dev20251004`)
3. Converts it to a date string (e.g., `2025-10-04`)
4. Fetches the corresponding commit hash from the PyTorch nightly branch at https://github.com/pytorch/pytorch/tree/nightly
5. Updates `.ci/docker/ci_commit_pins/pytorch.txt` with the new commit hash
6. Automatically stages the updated file for commit
1. **torch_pin sync** — when `torch_pin.py` is staged, updates the PyTorch commit
pin in `.ci/docker/ci_commit_pins/pytorch.txt` and syncs grafted c10 files.
2. **lintrunner** — runs `lintrunner -a --revision HEAD^ --skip MYPY` on changed
files. Auto-fixes formatting and blocks on lint errors. Soft-fails if lintrunner
is not installed. Runs `lintrunner init` automatically when `.lintrunner.toml`
changes.

### Installation
### pre-push

To install the Git hooks, run:
Delegates to `.git/hooks/pre-push` if one exists. This allows backend-specific
pre-push hooks (e.g., ARM's license and commit message checks) to work alongside
the repo-wide hooks.

## Installation

Hooks are installed automatically by `./install_executorch.sh`.

To install manually:

```bash
.githooks/install.sh
git config core.hooksPath .githooks
```

This will copy the pre-commit hook to `.git/hooks/` and make it executable.
### ARM backend pre-push

### Manual Usage

You can also run the update script manually at any time:
ARM contributors should additionally install the ARM-specific pre-push hook:

```bash
python .github/scripts/update_pytorch_pin.py
cp backends/arm/scripts/pre-push .git/hooks/
```

### Uninstalling
## Bypassing

To remove the pre-commit hook:
To skip hooks for a single commit or push:

```bash
rm .git/hooks/pre-commit
git commit --no-verify
git push --no-verify
```

## Troubleshooting

If the hook fails during a commit:
If the torch_pin hook fails:

1. Check that Python 3 is available in your PATH
2. Ensure you have internet connectivity to fetch commits from GitHub
3. Verify that the `NIGHTLY_VERSION` in `torch_pin.py` is in the correct format (`devYYYYMMDD`)
4. Make sure the corresponding nightly release exists in the PyTorch nightly branch

You can run the script manually to see detailed error messages:
If lintrunner fails:

```bash
python .github/scripts/update_pytorch_pin.py
```
1. Run `lintrunner init` to install linter tools
2. Check that your virtual environment is activated
23 changes: 0 additions & 23 deletions .githooks/install.sh

This file was deleted.

66 changes: 65 additions & 1 deletion .githooks/pre-commit
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,68 @@ if git diff --cached --name-only | grep -q "^torch_pin.py$"; then
fi
fi

exit 0
# --- lintrunner ---

if ! command -v lintrunner >/dev/null 2>&1; then
echo "Warning: lintrunner not found. Skipping lint checks."
echo "Install with: pip install lintrunner lintrunner-adapters && lintrunner init"
exit 0
fi

if [ ! -f .lintrunner.toml ]; then
echo "Warning: .lintrunner.toml not found. Skipping lint checks."
exit 0
fi

git_dir=$(git rev-parse --git-dir)

# Portable hash: sha256sum (Linux) or shasum (macOS)
if command -v sha256sum >/dev/null 2>&1; then
toml_hash=$(sha256sum .lintrunner.toml | cut -d' ' -f1)
else
toml_hash=$(shasum -a 256 .lintrunner.toml | cut -d' ' -f1)
fi
stored_hash=""
[ -f "${git_dir}/.lintrunner_init_hash" ] && stored_hash=$(cat "${git_dir}/.lintrunner_init_hash")

if [ "${toml_hash}" != "${stored_hash}" ]; then
echo "Running lintrunner init..."
if lintrunner init; then
echo "${toml_hash}" > "${git_dir}/.lintrunner_init_hash"
else
echo "lintrunner init failed. Run 'lintrunner init' manually."
exit 1
fi
fi

staged_files=$(git diff --cached --name-only --diff-filter=ACMR)

# Use HEAD^ if it exists (skip on initial commit)
revision_flag="--revision HEAD^"
if ! git rev-parse HEAD^ >/dev/null 2>&1; then
revision_flag=""
fi

lintrunner -a $revision_flag --skip MYPY
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.

Remind me why skip MYPY?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It is taking too much time and every time if the developer amends the commit, it might annoy them.

lint_status=$?

# Check if lintrunner modified any staged files. If so, block the commit
# so the user can review the changes before committing.
files_modified=0
while IFS= read -r path; do
[ -z "${path}" ] && continue
if ! git diff --quiet -- "${path}" 2>/dev/null; then
files_modified=1
break
fi
done <<< "${staged_files}"

if [ $files_modified -eq 1 ]; then
echo "Lintrunner modified files. Review with 'git diff', then 'git add -u && git commit'."
exit 1
fi

if [ $lint_status -ne 0 ]; then
echo "Lint errors found. Fix them and try again, or use 'git commit --no-verify' to skip."
exit 1
fi
9 changes: 9 additions & 0 deletions .githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#!/usr/bin/env bash

# Delegate to local pre-push hook if present (e.g., ARM backend).
# .githooks/ is set as core.hooksPath, so git won't look in .git/hooks/
# automatically. This passthrough ensures local hooks still run.
local_hook="$(git rev-parse --git-dir)/hooks/pre-push"
if [ -x "$local_hook" ]; then
"$local_hook" "$@"
fi
12 changes: 12 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,18 @@ lintrunner init
Then run `lintrunner` from the root of the repo to see its suggestions, or run
`lintrunner -a` to automatically apply the suggestions.

### Git Hooks

A pre-commit hook runs lintrunner automatically on every commit. Install it with:

```
git config core.hooksPath .githooks
```

This is also done automatically by `./install_executorch.sh`. If lintrunner
auto-fixes files, the commit will be blocked so you can review the changes with
`git diff` before re-committing.

### Python Style

ExecuTorch Python code follows the style used by the PyTorch core project.
Expand Down
8 changes: 5 additions & 3 deletions backends/arm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,14 @@ To run these tests, you need to install the required dependencies by running the
Please note that installing model test dependencies is a standalone process. When using the `--setup-test-dependency` flag,
the script will install only the necessary dependencies for model tests, skipping all other setup procedures.

## Using pre-commit
## Using git hooks

A pre-commit script is available in the backend to help developers. Follow the steps below to enable it:
The repo-wide pre-commit hook (lintrunner + torch_pin sync) is installed automatically
by `./install_executorch.sh`. To install the Arm-specific pre-push hook (license checks,
commit message format, docgen):

```
cp backends/arm/scripts/pre-commit .git/hooks/
cp backends/arm/scripts/pre-push .git/hooks/
```

## Notes on model specific and optional passes
Expand Down
22 changes: 0 additions & 22 deletions backends/arm/scripts/pre-commit

This file was deleted.

5 changes: 5 additions & 0 deletions install_executorch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,8 @@
# so we avoid repeated symlink segments in downstream CMake paths.
cd -- "$( realpath "$( dirname -- "${BASH_SOURCE[0]}" )" )" &> /dev/null || /bin/true
./run_python_script.sh ./install_executorch.py "$@"

# Install git hooks if inside a git repo
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.

What if someone else (IIRC Arm) installs their own pre-commit hooks, would it collide with that?

Also Arm has more scripts here for push etc - https://github.com/pytorch/executorch/tree/19bbeac41ab4ba21aa95a44d464e72b8da571302/backends/arm/scripts

We should consolidate.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

@digantdesai good point, it seems their pre-commit hook is a subset of what we are doing and pre-push hook is very arm specific, i think we can consolidate the pre-commit but pre-push we should leave it as-is, because it has some sign-off checks, commit format etc which might surprise others.

What i will do is we can let the installation via install_executorch take precedence per hook, and honor the backend's own hooks via thin wrapper and call them if installed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Please also CC arm POCs if needed as fyi.

if git rev-parse --git-dir > /dev/null 2>&1; then
git config core.hooksPath .githooks
fi
Loading