fix(deploy): stop hanging on per-file sticky-bit scan
Local Build and Deploy / deploy (push) Successful in 1m48s
Local Build and Deploy / deploy (push) Successful in 1m48s
Only clear paths that already have skip-worktree/assume-unchanged; keep nuclear src replace and content verify. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
3eaffe658d
commit
80c6559143
2 files changed
+26
-36
No files matched your search
@@ -47,53 +47,42 @@ jobs:
|
||||
git remote set-url origin /docker/gitea/gitea/git/repositories/remco/epicnext-cms.git/
|
||||
|
||||
# 3. Fetch and update code
|
||||
echo "Fetching origin/main..."
|
||||
git fetch origin --prune
|
||||
|
||||
# Clear EVERY skip-worktree / assume-unchanged bit. Those bits make
|
||||
# `git reset --hard` and `git diff` lie: the working tree can keep
|
||||
# ancient file contents while git reports a clean checkout.
|
||||
STICKY=0
|
||||
while IFS= read -r -d '' f; do
|
||||
if git ls-files -v -- "$f" | grep -qE '^[a-zS]'; then
|
||||
STICKY=$((STICKY + 1))
|
||||
fi
|
||||
git update-index --no-skip-worktree --no-assume-unchanged -- "$f" 2>/dev/null || true
|
||||
done < <(git ls-files -z)
|
||||
echo "Cleared skip-worktree/assume-unchanged bits (saw ${STICKY} sticky before clear)"
|
||||
# Only touch files that actually have sticky bits (fast). Clearing
|
||||
# every tracked path one-by-one can hang the runner for minutes.
|
||||
echo "Clearing sticky git index bits (if any)..."
|
||||
STICKY_LIST="$(git ls-files -v | awk '/^[a-zS]/ {print substr($0,3)}' || true)"
|
||||
if [ -n "${STICKY_LIST}" ]; then
|
||||
echo "${STICKY_LIST}" | while IFS= read -r f; do
|
||||
[ -n "$f" ] || continue
|
||||
git update-index --no-skip-worktree --no-assume-unchanged -- "$f" 2>/dev/null || true
|
||||
done
|
||||
echo "Cleared sticky bits on $(echo "${STICKY_LIST}" | grep -c . || true) path(s)"
|
||||
else
|
||||
echo "No sticky bits found"
|
||||
fi
|
||||
|
||||
echo "Hard reset to origin/main..."
|
||||
git reset --hard origin/main
|
||||
|
||||
# Nuclear: delete src/ on disk, then restore ONLY from git objects.
|
||||
# This is the only reliable way to drop host-local ghosts that survive
|
||||
# reset/checkout when index flags or permissions pin old bytes.
|
||||
# Defeats host-local ghosts that survive reset when index flags pin old bytes.
|
||||
echo "Nuclear-replacing src/ from HEAD..."
|
||||
rm -rf src
|
||||
git checkout -f HEAD -- src
|
||||
|
||||
# Drop other stray untracked junk under the app root (keep secrets/env).
|
||||
git clean -fd -e .env -e .env.local -e .env.production -e .env*.local
|
||||
|
||||
# Prove EVERY tracked file under src/ matches the HEAD blob (content hash).
|
||||
# `git diff` alone is not enough when skip-worktree was previously set.
|
||||
MISMATCH=0
|
||||
while IFS= read -r -d '' f; do
|
||||
case "$f" in
|
||||
src/*) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
expected="$(git rev-parse "HEAD:${f}")"
|
||||
actual="$(git hash-object "${f}")"
|
||||
if [ "${expected}" != "${actual}" ]; then
|
||||
echo "ERROR: content hash mismatch: ${f}" >&2
|
||||
echo " expected=${expected}" >&2
|
||||
echo " actual=${actual}" >&2
|
||||
MISMATCH=1
|
||||
fi
|
||||
done < <(git ls-files -z)
|
||||
if [ "${MISMATCH}" -ne 0 ]; then
|
||||
echo "ERROR: src/ working tree does not match HEAD after nuclear checkout" >&2
|
||||
# After sticky clear + nuclear replace, content diff is trustworthy again.
|
||||
if ! git diff --exit-code HEAD -- src >/dev/null; then
|
||||
echo "ERROR: src/ still differs from HEAD after nuclear checkout:" >&2
|
||||
git diff --stat HEAD -- src >&2 || true
|
||||
exit 1
|
||||
fi
|
||||
echo "Verified all tracked src/ blobs match HEAD"
|
||||
echo "Verified src/ matches HEAD"
|
||||
|
||||
# Drop incremental TS caches that can hide real type errors.
|
||||
rm -f tsconfig.tsbuildinfo .tsbuildinfo
|
||||
|
||||
@@ -24,13 +24,14 @@ describe("production deploy workflow", () => {
|
||||
expect(resetAt).toBeGreaterThan(reclaimAt);
|
||||
});
|
||||
|
||||
it("nuclear-replaces src/ and verifies every tracked blob hash", () => {
|
||||
it("nuclear-replaces src/ and clears sticky bits without scanning every path", () => {
|
||||
expect(workflow).toContain("rm -rf src");
|
||||
expect(workflow).toContain("git checkout -f HEAD -- src");
|
||||
expect(workflow).toContain("git hash-object");
|
||||
expect(workflow).toContain("no-skip-worktree");
|
||||
expect(workflow).toContain("no-assume-unchanged");
|
||||
expect(workflow).toContain("Verified all tracked src/ blobs match HEAD");
|
||||
expect(workflow).toContain("Verified src/ matches HEAD");
|
||||
expect(workflow).toContain("git ls-files -v");
|
||||
expect(workflow).not.toContain("git ls-files -z");
|
||||
expect(workflow).toContain("pnpm typecheck");
|
||||
});
|
||||
|
||||
|
||||
Reference in new issue
Block a user