Description
This RFC proposes extending `tools/git/hooks/pre-push` to honor an optional `STDLIB_DIFF_BASE` environment variable that overrides the hook's current file-set computation.
Today, the `pre-push` hook computes the list of files to validate with:
```sh
git diff --cached "${remote}/${GIT_CURRENT_BRANCH}"
```
i.e. "everything in the current branch that the remote tracking ref doesn't have yet." For short-lived feature branches this is exactly right.
For long-lived branches (e.g. integration branches carrying catalog/docs/changelog work for weeks or months), this definition is wrong in a specific way: after every periodic `git merge develop` the hook sees all merged-in develop commits as "not yet pushed" and therefore tries to run lint / benchmarks / examples / tests against hundreds of files that already passed on `develop`. The validation is not only wasteful — it often fails locally (missing native deps for a package the maintainer never touched) and blocks pushing genuinely correct work.
The local workaround stdlib already supports is to scope Make targets to `develop...HEAD` (three-dot, merge-base-relative) and use the `FILES=`-scoped variants:
```sh
git diff --name-only develop...HEAD > /tmp/files.txt
make lint-files FILES="$(cat /tmp/files.txt | ...)"
```
This RFC proposes exposing the same knob to the hook so there is one source of truth for "which files belong to this branch's work":
```sh
diff_base="${STDLIB_DIFF_BASE:-${remote}/${GIT_CURRENT_BRANCH}}"
files="$(git diff --name-only "${diff_base}")"
```
A maintainer of a long-lived branch would then:
```sh
STDLIB_DIFF_BASE=develop...HEAD git push origin my-long-lived-branch
```
Default behavior is unchanged — if `STDLIB_DIFF_BASE` is unset, the hook computes the file set exactly as it does today.
Related Issues
Related to #11501 (worktree hook fix — same family of long-lived-branch hook friction).
Questions
- Is `STDLIB_DIFF_BASE` the right name? Alternatives: `STDLIB_HOOK_DIFF_BASE`, `STDLIB_PREPUSH_DIFF_BASE`. A generic `STDLIB_DIFF_BASE` is reusable across other hooks later (e.g. `pre-commit` for conflict-merge commits), but that generality may be more than is wanted right now.
- Should the variable be documented in `CONTRIBUTING.md`, in the hook source, or only in a dedicated long-lived-branch operations doc? The use case is narrow; over-promoting it could invite misuse on short-lived branches.
- Should the hook validate that the resolved `diff_base` is reachable and emit a clear error if not, or fall back to the default silently?
Other
Concretely the diff is small — roughly two lines at the top of the hook:
```diff
- files=$(git diff --cached "${remote}/${GIT_CURRENT_BRANCH}" --name-only --diff-filter=d)
- diff_base="${STDLIB_DIFF_BASE:-${remote}/${GIT_CURRENT_BRANCH}}"
- files=$(git diff "${diff_base}" --name-only --diff-filter=d)
```
(exact invocation depends on whether `--cached` is desired when an explicit `STDLIB_DIFF_BASE` is passed; I'd expect not, since the three-dot form already implies "committed but not on base").
Checklist
Description
This RFC proposes extending `tools/git/hooks/pre-push` to honor an optional `STDLIB_DIFF_BASE` environment variable that overrides the hook's current file-set computation.
Today, the `pre-push` hook computes the list of files to validate with:
```sh
git diff --cached "${remote}/${GIT_CURRENT_BRANCH}"
```
i.e. "everything in the current branch that the remote tracking ref doesn't have yet." For short-lived feature branches this is exactly right.
For long-lived branches (e.g. integration branches carrying catalog/docs/changelog work for weeks or months), this definition is wrong in a specific way: after every periodic `git merge develop` the hook sees all merged-in develop commits as "not yet pushed" and therefore tries to run lint / benchmarks / examples / tests against hundreds of files that already passed on `develop`. The validation is not only wasteful — it often fails locally (missing native deps for a package the maintainer never touched) and blocks pushing genuinely correct work.
The local workaround stdlib already supports is to scope Make targets to `develop...HEAD` (three-dot, merge-base-relative) and use the `FILES=`-scoped variants:
```sh
git diff --name-only develop...HEAD > /tmp/files.txt
make lint-files FILES="$(cat /tmp/files.txt | ...)"
```
This RFC proposes exposing the same knob to the hook so there is one source of truth for "which files belong to this branch's work":
```sh
diff_base="${STDLIB_DIFF_BASE:-${remote}/${GIT_CURRENT_BRANCH}}"
files="$(git diff --name-only "${diff_base}")"
```
A maintainer of a long-lived branch would then:
```sh
STDLIB_DIFF_BASE=develop...HEAD git push origin my-long-lived-branch
```
Default behavior is unchanged — if `STDLIB_DIFF_BASE` is unset, the hook computes the file set exactly as it does today.
Related Issues
Related to #11501 (worktree hook fix — same family of long-lived-branch hook friction).
Questions
Other
Concretely the diff is small — roughly two lines at the top of the hook:
```diff
```
(exact invocation depends on whether `--cached` is desired when an explicit `STDLIB_DIFF_BASE` is passed; I'd expect not, since the three-dot form already implies "committed but not on base").
Checklist