Skip to content

chore: add pre-push hook guarding yarn.lock drift - #1220

Open
Martin Hochel (Hotell) wants to merge 1 commit into
microsoft:mainfrom
Hotell:chore/pre-push-lockfile-guard
Open

chore: add pre-push hook guarding yarn.lock drift#1220
Martin Hochel (Hotell) wants to merge 1 commit into
microsoft:mainfrom
Hotell:chore/pre-push-lockfile-guard

Conversation

@Hotell

Copy link
Copy Markdown
Collaborator

Problem

CI runs yarn install --immutable, but that check only ever inspects the working tree.
A lockfile that was regenerated locally and never committed therefore passes locally and
fails on CI.

That is exactly what happened in #1219: peerDependencies were edited after yarn add,
the lockfile was regenerated at some later point but the commit kept the stale copy, and
a local yarn install --immutable still reported success because it was validating the
repaired working tree rather than the commit.

The gap

Two distinct failure modes exist, and --immutable only covers one:

Failure mode Caught by --immutable?
Manifest changed, lockfile not regenerated yes
Lockfile regenerated, but not committed no

Change

A .husky/pre-push hook covering both:

if ! git diff --quiet HEAD -- yarn.lock; then
  echo "pre-push: yarn.lock differs from HEAD. Commit it before pushing." >&2
  exit 1
fi

yarn install --immutable

The git check runs first because it is essentially free; --immutable is a read-only
no-op when the tree is already in sync, so the hook adds no meaningful cost to a normal push.

Note that git status --porcelain is unsuitable here: it exits 0 even when it prints
output, so it cannot gate a hook. git diff --quiet HEAD returns non-zero and covers both
staged and unstaged drift.

Verification

Scenario Expected Actual
Clean, in-sync tree pass exit 0
yarn.lock modified but uncommitted block exit 1, yarn.lock differs from HEAD
peerDependencies added with stale lock block exit 1, YN0028

This PR's own push exercised the hook.

CI runs `yarn install --immutable`, but that check only ever inspects the working
tree. A lockfile that was regenerated locally and never committed therefore passes
locally and fails on CI, which is exactly what happened in microsoft#1219.

The hook closes both gaps:

- `git diff --quiet HEAD -- yarn.lock` rejects a lockfile that differs from the
  commit being pushed (staged or unstaged)
- `yarn install --immutable` rejects a manifest change, including peerDependencies,
  with no matching lockfile update

Both are no-ops when everything is in sync.
@github-actions

Copy link
Copy Markdown

📋 PR Validation Summary

Check the Build react library job summary for detailed reports:

  • 📦 Bundle Size — size comparison against the base branch

To view: click the link above → select the Build react library job → open the Summary tab.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Adds a Husky pre-push hook to prevent pushing when yarn.lock has drifted locally (including the “lockfile regenerated but not committed” case that yarn install --immutable alone won’t catch), aligning local checks with CI expectations.

Changes:

  • Add .husky/pre-push hook that blocks pushes when yarn.lock differs from HEAD.
  • Run yarn install --immutable during pre-push to catch manifest/lockfile mismatches before pushing.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@Hotell
Martin Hochel (Hotell) marked this pull request as ready for review August 24, 2026 09:48
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