Exclude URL-keyed promisor entries from git fetch --all · Entire
Exclude URL-keyed promisor entries from git fetch --all
d9df8fc→main·
toothbrush·4d ago·2 files·+166 added/-1 removed
Every filtered checkpoint fetch from a URL leaves a remote.
Changes
2
cmd/entire/cli/checkpoint/remote
Mgit.go+54/-1
Mgit_test.go+112
3 unmodified lines
4
5
6
7
8
9
10
1 unmodified line
12
13
14
15
16
17
18
59 unmodified lines
78
79
80
79
81
82
83
84
85
8 unmodified lines
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
3 unmodified lines
"context"
"encoding/base64"
"fmt"
"log/slog"
"os"
"os/exec"
"path/filepath"
1 unmodified line
"strings"
"sync"
"github.com/entireio/cli/cmd/entire/cli/logging"
"github.com/entireio/cli/cmd/entire/cli/settings"
}
// markPromisorEntrySkipped excludes the URL-keyed config section that git
// creates for a filtered URL fetch (remote.<url>.promisor=true) from
// `git fetch --all` and `git remote update`. Git needs the promisor entry to
// lazy-fetch filtered-out objects later, but the entry also makes the URL show
// up as a fetchable remote, so without this every checkpoint URL ever fetched
// from lingers as a phantom remote that bulk fetches keep dialing.
// Best-effort: the fetch already succeeded, so failures only log.
func markPromisorEntrySkipped(ctx context.Context, dir, url string) {
if !gitConfigBool(ctx, dir, "remote."+url".promisor") {
// Git didn't record a promisor entry for this URL; don't invent a
// config section that wouldn't otherwise exist.
return
}
if gitConfigBool(ctx, dir, "remote."+url".skipFetchAll") {
return
}
for _, key := range []string{"skipFetchAll", "skipDefaultUpdate"} {
cmd := exec.CommandContext(ctx, "git", "config", "--local", "remote."+url+"."+key, "true")
if dir != "" {
cmd.Dir = dir
}
if out, cfgErr := cmd.CombinedOutput(); cfgErr != nil {
logging.Warn(ctx, "failed to mark promisor config entry as skipped for bulk fetches",
slog.String("url", RedactURL(url)),
slog.String("key", key),
slog.String("output", strings.TrimSpace(string(out))),
slog.String("error", cfgErr.Error()),
)
return
}
}
}
// FetchBlobs fetches specific objects (typically blobs) by hash from a remote.
// Uses `git fetch-pack` rather than `git fetch` because the high-level
// porcelain enforces partial-clone integrity checks that reject blob-only
// TestFetch_FilteredURLFetchMarksPromisorSkipped verifies that after a
// filtered fetch from a URL, the URL-keyed promisor config section git creates
// is excluded from `git fetch --all` / `git remote update` — otherwise every
// checkpoint URL ever fetched from lingers as a phantom remote that bulk
// fetches keep dialing.
func TestFetch_FilteredURLFetchMarksPromisorSkipped(t *testing.T) {
ctx := context.Background()
tmpDir := t.TempDir()
originBare := filepath.Join(tmpDir, "origin.git")
checkpointBare := filepath.Join(tmpDir, "checkpoints.git")
seedDir := filepath.Join(tmpDir, "seed")
cloneDir := filepath.Join(tmpDir, "clone")
testutil.InitRepo(t, seedDir)
testutil.WriteFile(t, seedDir, "f.txt", "init")
testutil.GitAdd(t, seedDir, "f.txt")
testutil.GitCommit(t, seedDir, "init")
// Separate origin and checkpoint repos, mirroring the real setup where
// checkpoints are fetched by URL from a repo that is not origin.
runIsolatedGit(ctx, t, "", "init", "--bare", originBare)
runIsolatedGit(ctx, t, "", "init", "--bare", checkpointBare)
runIsolatedGit(ctx, t, checkpointBare, "config", "uploadpack.allowFilter", "true")
runIsolatedGit(ctx, t, seedDir, "push", originBare, "HEAD:refs/heads/main")
runIsolatedGit(ctx, t, "", "clone", "--branch", "main", "file://"+originBare, cloneDir)
// A commit only in the checkpoint repo so the filtered fetch has
// something to transfer.
testutil.WriteFile(t, seedDir, "f.txt", "init\nnext\n")
testutil.GitAdd(t, seedDir, "f.txt")
testutil.GitCommit(t, seedDir, "next")
runIsolatedGit(ctx, t, seedDir, "push", checkpointBare, "HEAD:refs/heads/main")
// Filtered fetches read .entire settings from the CWD repo.
testutil.WriteFile(
t,
cloneDir,
".entire/settings.json",
`{"enabled": true, "strategy_options": {"filtered_fetches": true}}`,
)
t.Chdir(cloneDir)
fetchURL := "file://" + checkpointBare
out, err := Fetch(ctx, FetchOptions{
Remote: fetchURL,
RefSpecs: []string{"+refs/heads/main:refs/entire-fetch-tmp/main"},
NoTags: true,
Dir: cloneDir,
})
require.NoError(t, err, "fetch output: %s", out)
// Sanity: git recorded the URL-keyed promisor entry for the filtered fetch.
require.True(t, gitConfigBool(ctx, cloneDir, "remote."+fetchURL+".promisor"),
"expected git to record a promisor entry for the filtered URL fetch")
assert.True(t, gitConfigBool(ctx, cloneDir, "remote."+fetchURL+".skipFetchAll"),
"URL-keyed promisor entry should be excluded from git fetch --all")
assert.True(t, gitConfigBool(ctx, cloneDir, "remote."+fetchURL+".skipDefaultUpdate"),
"URL-keyed promisor entry should be excluded from git remote update")
// git fetch --all must no longer dial the phantom entry: with the
// checkpoint repo gone, --all only succeeds if the URL-keyed entry is
// skipped (origin is still reachable).
require.NoError(t, os.RemoveAll(checkpointBare))
runIsolatedGit(ctx, t, cloneDir, "fetch", "--all", "--no-auto-gc")
}
// TestFetch_UnfilteredFetchDoesNotCreateConfigSection verifies the stamp is
// gated on git having created a promisor entry: a plain (unfiltered) URL fetch
// must not invent a remote.<url> config section.
func TestFetch_UnfilteredFetchDoesNotCreateConfigSection(t *testing.T) {
ctx := context.Background()
tmpDir := t.TempDir()
bareDir := filepath.Join(tmpDir, "bare.git")
seedDir := filepath.Join(tmpDir, "seed")
cloneDir := filepath.Join(tmpDir, "clone")
testutil.InitRepo(t, seedDir)
testutil.WriteFile(t, seedDir, "f.txt", "init")
testutil.GitAdd(t, seedDir, "f.txt")
testutil.GitCommit(t, seedDir, "init")
runIsolatedGit(ctx, t, "", "init", "--bare", bareDir)
runIsolatedGit(ctx, t, seedDir, "remote", "add", "origin", bareDir)
runIsolatedGit(ctx, t, seedDir, "push", "origin", "HEAD:refs/heads/main")
runIsolatedGit(ctx, t, "", "clone", "--branch", "main", "file://"+bareDir, cloneDir)
testutil.WriteFile(
t,
cloneDir,
".entire/settings.json",
`{"enabled": true, "strategy_options": {"filtered_fetches": true}}`,
)
t.Chdir(cloneDir)
fetchURL := "file://" + bareDir
out, err := Fetch(ctx, FetchOptions{
Remote: fetchURL,
RefSpecs: []string{"+refs/heads/main:refs/remotes/origin/main"},
NoTags: true,
NoFilter: true,
Dir: cloneDir,
})
require.NoError(t, err, "fetch output: %s", out)
assert.False(t, gitConfigBool(ctx, cloneDir, "remote."+fetchURL+".promisor"))
assert.False(t, gitConfigBool(ctx, cloneDir, "remote."+fetchURL+".skipFetchAll"))
assert.False(t, gitConfigBool(ctx, cloneDir, "remote."+fetchURL+".skipDefaultUpdate"))
}