From c3e9ac87a7f80dae4bf4c6869e932fa7cf2dd4c4 Mon Sep 17 00:00:00 2001 From: ethernet Date: Thu, 24 Sep 2026 00:51:07 -0400 Subject: [PATCH] fix(installer): clone treeless instead of full history A --depth 1 clone hides the release tag runtime identity is derived from and cannot resolve a non-tip --commit pin or the ancestor guard; a full clone downloads every tree and blob ever committed. --filter=tree:0 keeps the whole commit graph and its tags and fetches trees on demand: 125M vs 77M for --depth 1 against GitHub, identity exact. The deferred-checkout fallback uses the same filter. --- scripts/install.ps1 | 14 +++++++++----- scripts/install.sh | 15 +++++++++------ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/scripts/install.ps1 b/scripts/install.ps1 index fa26d97b7d..ab575d44a3 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -633,16 +633,20 @@ function Stage-Repository { try { $cloned = $false foreach ($attempt in 1..3) { - Invoke-Native { git clone --branch $Branch $RepoUrl $tree } + # Treeless: every commit and release tag (runtime identity is the + # nearest reachable release; -Commit pins and branch switches + # still resolve), trees and blobs fetched on demand, so the + # download stays close to a --depth 1 clone. + Invoke-Native { git clone --filter=tree:0 --branch $Branch $RepoUrl $tree } if (-not $LASTEXITCODE) { $cloned = $true; break } Remove-Item -LiteralPath $tree -Recurse -Force -ErrorAction SilentlyContinue if ($attempt -lt 3) { Start-Sleep -Seconds ($attempt * 5) } } if (-not $cloned) { - # Full history, blobs on demand: -Commit, tags and later branch - # switches all still resolve. - Log "direct clone failed; trying deferred blob download" - Invoke-Native { git clone --filter=blob:none --no-checkout --branch $Branch $RepoUrl $tree } + # The checkout step is where throttled downloads die: clone the + # graph alone, then retry materializing the tree separately. + Log "direct clone failed; trying deferred checkout" + Invoke-Native { git clone --filter=tree:0 --no-checkout --branch $Branch $RepoUrl $tree } if (-not $LASTEXITCODE) { foreach ($attempt in 1..2) { Invoke-Native { git -C $tree reset --hard HEAD } diff --git a/scripts/install.sh b/scripts/install.sh index 58b0ace8bd..ce7108edbc 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -380,7 +380,11 @@ stage_repository() { local staged attempt cloned=false staged="$(mktemp -d "$(dirname "$INSTALL_DIR")/.hermes-clone-XXXXXX")" || fail "cannot stage clone" for attempt in 1 2 3; do - if git clone --branch "$BRANCH" "$REPO_URL" "$staged/tree"; then + # Treeless: every commit and release tag (runtime identity is the + # nearest reachable release; --commit pins and branch switches + # still resolve), trees and blobs fetched on demand, so the + # download stays close to a --depth 1 clone. + if git clone --filter=tree:0 --branch "$BRANCH" "$REPO_URL" "$staged/tree"; then cloned=true break fi @@ -388,11 +392,10 @@ stage_repository() { [ "$attempt" = 3 ] || sleep "$((attempt * 5))" done if [ "$cloned" = false ]; then - # Full history, blobs on demand: --commit, tags and later branch - # switches all still resolve (a shallow single-branch clone - # could not check out anything but the tip). - log "direct clone failed; trying deferred blob download" - if git clone --filter=blob:none --no-checkout \ + # The checkout step is where throttled downloads die: clone the + # graph alone, then retry materializing the tree separately. + log "direct clone failed; trying deferred checkout" + if git clone --filter=tree:0 --no-checkout \ --branch "$BRANCH" "$REPO_URL" "$staged/tree"; then for attempt in 1 2; do if git -C "$staged/tree" reset --hard HEAD; then