From 5dc9fe049f5f9a9a634a566354bf25958e74b942 Mon Sep 17 00:00:00 2001 From: Lars Francke Date: Tue, 28 Jul 2026 17:23:02 +0200 Subject: [PATCH 1/2] fix: Fetch complete release-branch trees in netlify-fetch Production builds failed with antora unable to find object e9b0f5de on release-26.7. That object is the ui/NOTICE blob: release-26.7 is the first release branch cut after the UI was vendored into this repo, so ui/ is regular content there instead of a submodule gitlink - and the blob-materializing loop excluded ui/ from its pathspec checkouts, a rule written when every release branch still had the submodule. Antora reads the whole tree of a content branch with isomorphic-git, which cannot fetch missing objects on demand, and died on the first ui blob. Reproduced and verified against a fresh blobless clone: with the exclusion the exact production error appears, without it the build passes and no tip objects are missing. Dropping the exclusion is harmless for the old branches: a gitlink has no blobs to fetch. Additional hardening while in here: - branch list from git ls-remote instead of the cached remote-tracking refs (make expanded the old list before the fetch even ran, so a brand-new release branch was invisible to its first build) - no more silent failures: set -e and no -q on fetch abort the build at the failing command instead of surfacing later as a confusing antora error - gc.auto=0 inside the loop and git fetch --all --prune keep the long-lived netlify build cache tidy and race-free --- Makefile | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/Makefile b/Makefile index 7ff8debc8..e9bbb12f8 100644 --- a/Makefile +++ b/Makefile @@ -54,20 +54,25 @@ clean: rm -rf cache # The netlify repo is checked out without any blobs. Antora needs local -# release branches and their blobs in the object database, so this target -# creates/updates the local branches and materializes their blobs via -# pathspec checkouts - without ever switching HEAD (enabling branch previews!). -# ui/ is excluded: release branches still reference it as a submodule and -# its blobs are not needed (the UI bundle is built from the current checkout). +# release branches and their complete tip trees in the object database (it +# reads them with isomorphic-git, which cannot fetch missing objects on +# demand), so this target creates/updates the local branches and +# materializes their blobs via pathspec checkouts - without ever switching +# HEAD (enabling branch previews!). netlify-fetch: # netlify messes with some files, restore everything to how it was: git reset --hard # fetch, because netlify does caching and we want to get the latest commits - git fetch --all - for remote in $(shell git branch -r | grep -E 'release[/-]'); do \ - branch="$${remote#origin/}"; \ - git fetch -q origin "+refs/heads/$$branch:refs/heads/$$branch"; \ - git checkout -q "$$branch" -- ':(exclude)ui' . ; \ + git fetch --all --prune + # The branch list comes from the remote so it is current even on the first + # build after a new release branch appears (the cached remote-tracking refs + # lag behind). Auto-gc is disabled inside the loop: a background gc can + # race the ref updates and silently leave a stale local branch behind, + # which only surfaces much later as a missing-object error from antora. + # Failures abort the build immediately instead. + set -e; for branch in $$(git ls-remote --heads origin | sed 's|.*refs/heads/||' | grep -E 'release[/-]'); do \ + git -c gc.auto=0 fetch origin "+refs/heads/$$branch:refs/heads/$$branch"; \ + git -c gc.auto=0 checkout -q "$$branch" -- . ; \ done # restore the working tree of the current commit and drop files that # only exist on other branches (ignored files like node_modules stay) From 04f28648e8dbe4ad19123abbf462a54f8b4405e9 Mon Sep 17 00:00:00 2001 From: Lars Francke Date: Tue, 28 Jul 2026 18:02:01 +0200 Subject: [PATCH 2/2] fix: Guard netlify-fetch against a failing branch listing Review feedback (set -e at the top / pipefail): make runs every recipe line in its own shell, so a leading set -e would only govern itself, and the shell is sh, which has no pipefail - but the spirit of the comment found a real gap: a failing ls-remote inside the command substitution would have silently emptied the loop. The list is now captured and checked explicitly, and set -eu replaces set -e. --- Makefile | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index e9bbb12f8..50c4b63e0 100644 --- a/Makefile +++ b/Makefile @@ -70,7 +70,10 @@ netlify-fetch: # race the ref updates and silently leave a stale local branch behind, # which only surfaces much later as a missing-object error from antora. # Failures abort the build immediately instead. - set -e; for branch in $$(git ls-remote --heads origin | sed 's|.*refs/heads/||' | grep -E 'release[/-]'); do \ + set -eu; \ + branches="$$(git ls-remote --heads origin | sed 's|.*refs/heads/||' | grep -E 'release[/-]')"; \ + [ -n "$$branches" ] || { echo "netlify-fetch: no release branches from ls-remote - refusing to continue"; exit 1; }; \ + for branch in $$branches; do \ git -c gc.auto=0 fetch origin "+refs/heads/$$branch:refs/heads/$$branch"; \ git -c gc.auto=0 checkout -q "$$branch" -- . ; \ done