Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
b9f2eee
setup: split up concerns of `init_db()`
pks-t Sep 10, 2026
d73f69c
builtin/clone: defer setup of the object database
pks-t Sep 10, 2026
b781ec0
builtin/clone: move around `setup_reference()`
pks-t Sep 10, 2026
e6ea2e2
builtin/clone: refactor handling of "--reference{,-if-able}"
pks-t Sep 10, 2026
bbf30b6
builtin/clone: move setup of alternates for shared local clones
pks-t Sep 10, 2026
4f21bd0
builtin/clone: move setup of alternates for non-shared local clones
pks-t Sep 10, 2026
fdfff05
odb/source: support writing alternates when creating the database
pks-t Sep 10, 2026
7f2a360
builtin/clone: write alternates via `odb_create_on_disk()`
pks-t Sep 10, 2026
04541ec
fixup! odb: scan all sources' packfiles before loose objects
dscho Oct 16, 2026
d798561
odb/source: remove the ability to write alternates
pks-t Sep 10, 2026
6e60467
gvfs-helper: use the upstream in-memory alternates API
dscho Oct 27, 2026
4a7c3ef
commit-graph: require resolved packfile paths for `stdin_packs`
pks-t Oct 8, 2026
21fc7d2
commit-graph: stop depending on `struct odb_source`
pks-t Oct 8, 2026
560d1af
odb/source-files: introduce `struct odb_files_dir`
pks-t Oct 8, 2026
d2e44dd
gvfs-helper: follow the files directory abstraction
dscho Oct 27, 2026
a26be26
odb: refactor `odb_for_each_alternate()` to yield dirs
pks-t Oct 8, 2026
c8e0fda
odb: refactor `odb_find_source()` to yield dirs
pks-t Oct 8, 2026
b2e69b3
odb/source-files: add the ability to have multiple object dirs
pks-t Oct 8, 2026
0881c5b
tmp-objdir: absorb logic to set and restore primary sources
pks-t Oct 8, 2026
31a06db
maintenance: avoid replacing the primary object source
dscho Oct 27, 2026
81df0eb
tmp-objdir: manage quarantine as an object directory
pks-t Oct 8, 2026
6ed9dac
tmp-objdir: replace primary source at creation time
pks-t Oct 8, 2026
d192bf5
odb/source: make `will_destroy` an implementation detail
pks-t Oct 8, 2026
587cf2d
odb/source-files: extract reading alternates
pks-t Oct 8, 2026
db22493
odb/source-files: move alternates into the backend
pks-t Oct 8, 2026
cf95d9c
gvfs: preserve shared-cache alternates in the files backend
dscho Oct 27, 2026
1429894
gvfs-helper: track the directory receiving fetched objects
dscho Oct 27, 2026
f9cf712
maintenance: follow the primary files source
dscho Oct 27, 2026
9eb7413
odb/source-files: fix performance when reading objects with alternates
pks-t Oct 15, 2026
5a64a86
odb/source: drop `read_alternates` callback
pks-t Oct 8, 2026
b8f8532
odb/source-files: fix performance when streaming objects with alternates
pks-t Oct 15, 2026
b5ffbf2
Merge branch 'ps/odb-alternates-at-creation'
dscho Oct 19, 2026
fa4f86f
Merge branch 'ps/odb-files-alternates' into jch
dscho Oct 19, 2026
4414e65
odb/source-files: make the second read an implementation detail
pks-t Oct 15, 2026
cd2bb45
read-object: preserve quick-lookup gating after backend retries
dscho Oct 27, 2026
6f84a9d
odb: remove read loop for found objects
pks-t Oct 15, 2026
ee114d7
gvfs: retain retries after removing the ODB read loop
dscho Oct 27, 2026
b6e1843
odb: don't try re-fetching corrupt objects
pks-t Oct 15, 2026
dc1ccd9
gvfs: preserve read results and failure diagnostics
dscho Oct 27, 2026
1e21818
odb/source: drop `local` flag
pks-t Oct 15, 2026
3938f72
Merge branch 'ps/odb-files-alternates-cleanups' into seen
dscho Oct 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 69 additions & 42 deletions builtin/clone.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,42 +154,34 @@ static char *get_repo_path(const char *repo, int *is_bundle)
return canon;
}

static int add_one_reference(struct string_list_item *item, void *cb_data)
struct collect_alternates_data {
struct strvec *alternates;
bool required;
};

static int collect_one_alternate(struct string_list_item *item, void *cb_data)
{
struct collect_alternates_data *data = cb_data;
struct strbuf err = STRBUF_INIT;
int *required = cb_data;
char *ref_git = compute_alternate_path(item->string, &err);

if (!ref_git) {
if (*required)
if (data->required)
die("%s", err.buf);
else
fprintf(stderr,
_("info: Could not add alternate for '%s': %s\n"),
item->string, err.buf);
} else {
struct strbuf sb = STRBUF_INIT;
strbuf_addf(&sb, "%s/objects", ref_git);
odb_add_to_alternates_file(the_repository->objects, sb.buf);
strbuf_release(&sb);
strvec_pushf(data->alternates, "%s/objects", ref_git);
}

strbuf_release(&err);
free(ref_git);
return 0;
}

static void setup_reference(void)
{
int required = 1;
for_each_string_list(&option_required_reference,
add_one_reference, &required);
required = 0;
for_each_string_list(&option_optional_reference,
add_one_reference, &required);
}

static void copy_alternates(struct strbuf *src, const char *src_repo)
static void read_alternates(struct strvec *alternates, const char *src_repo)
{
/*
* Read from the source objects/info/alternates file
Expand All @@ -203,29 +195,70 @@ static void copy_alternates(struct strbuf *src, const char *src_repo)
* to turn entries with paths relative to the original
* absolute, so that they can be used in the new repository.
*/
FILE *in = xfopen(src->buf, "r");
FILE *in;
struct strbuf path = STRBUF_INIT;
struct strbuf line = STRBUF_INIT;

strbuf_addf(&path, "%s/objects/info/alternates", src_repo);

in = fopen(path.buf, "r");
if (!in) {
if (errno == ENOENT)
goto out;
die_errno("could not read alternates file '%s'", path.buf);
}

while (strbuf_getline(&line, in) != EOF) {
char *abs_path;
if (!line.len || line.buf[0] == '#')
continue;
if (is_absolute_path(line.buf)) {
odb_add_to_alternates_file(the_repository->objects,
line.buf);
strvec_push(alternates, line.buf);
continue;
}
abs_path = mkpathdup("%s/objects/%s", src_repo, line.buf);
if (!normalize_path_copy(abs_path, abs_path))
odb_add_to_alternates_file(the_repository->objects,
abs_path);
strvec_push(alternates, abs_path);
else
warning("skipping invalid relative alternate: %s/%s",
src_repo, line.buf);
free(abs_path);
}

out:
strbuf_release(&path);
strbuf_release(&line);
fclose(in);
if (in)
fclose(in);
}

static void collect_alternates(struct strvec *alternates,
const char *local_source_repo)
{
if (option_required_reference.nr || option_optional_reference.nr) {
struct collect_alternates_data data = {
.alternates = alternates,
.required = true,
};

for_each_string_list(&option_required_reference,
collect_one_alternate, &data);
data.required = false;
for_each_string_list(&option_optional_reference,
collect_one_alternate, &data);
}

if (local_source_repo) {
struct strbuf commondir = STRBUF_INIT;

get_common_dir(&commondir, local_source_repo);
if (option_shared)
strvec_pushf(alternates, "%s/objects", commondir.buf);
else
read_alternates(alternates, commondir.buf);

strbuf_release(&commondir);
}
}

static void mkdir_if_missing(const char *pathname, mode_t mode)
Expand Down Expand Up @@ -301,11 +334,9 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
continue;
}

/* Files that cannot be copied bit-for-bit... */
if (!fspathcmp(iter->relative_path, "info/alternates")) {
copy_alternates(src, src_repo);
/* Alternates were already handled earlier. */
if (!fspathcmp(iter->relative_path, "info/alternates"))
continue;
}

if (unlink(dest->buf) && errno != ENOENT)
die_errno(_("failed to unlink '%s'"), dest->buf);
Expand Down Expand Up @@ -349,13 +380,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,

static void clone_local(const char *src_repo, const char *dest_repo)
{
if (option_shared) {
struct strbuf alt = STRBUF_INIT;
get_common_dir(&alt, src_repo);
strbuf_addstr(&alt, "/objects");
odb_add_to_alternates_file(the_repository->objects, alt.buf);
strbuf_release(&alt);
} else {
if (!option_shared) {
struct strbuf src = STRBUF_INIT;
struct strbuf dest = STRBUF_INIT;
get_common_dir(&src, src_repo);
Expand Down Expand Up @@ -999,6 +1024,7 @@ int cmd_clone(int argc,
N_("uri"), N_("a URI for downloading bundles before fetching from origin remote")),
OPT_END()
};
struct strvec alternates = STRVEC_INIT;

const char * const builtin_clone_usage[] = {
N_("git clone [<options>] [--] <repo> [<dir>]"),
Expand Down Expand Up @@ -1185,10 +1211,9 @@ int cmd_clone(int argc,
* repository, and reference backends may persist that information into
* their on-disk data structures.
*/
init_db(the_repository, git_dir, real_git_dir, work_tree, option_template,
GIT_HASH_UNKNOWN, ref_storage_format, NULL,
do_not_override_repo_unix_permissions,
INIT_DB_QUIET | INIT_DB_SKIP_REFDB);
create_repository(the_repository, git_dir, real_git_dir, work_tree,
option_template, GIT_HASH_UNKNOWN, ref_storage_format,
do_not_override_repo_unix_permissions, NULL);

if (real_git_dir) {
free((char *)git_dir);
Expand Down Expand Up @@ -1311,9 +1336,6 @@ int cmd_clone(int argc,
strbuf_reset(&key);
}

if (option_required_reference.nr || option_optional_reference.nr)
setup_reference();

remote = remote_get_early(remote_name);

if (!option_rev)
Expand Down Expand Up @@ -1342,6 +1364,9 @@ int cmd_clone(int argc,
if (option_local > 0 && !is_local)
warning(_("--local is ignored"));

collect_alternates(&alternates, is_local ? path : NULL);
create_object_database(the_repository, &alternates);

transport = transport_get(remote, path ? path : remote->url.v[0]);
transport_set_verbosity(transport, option_verbosity, option_progress);
transport->family = family;
Expand Down Expand Up @@ -1445,6 +1470,7 @@ int cmd_clone(int argc,
initialize_repository_version(the_repository, hash_algo, the_repository->ref_storage_format, 1);
repo_set_hash_algo(the_repository, hash_algo);
create_reference_database(the_repository, NULL, 1);
startup_info->have_repository = 1;

/*
* Before fetching from the remote, download and install bundle
Expand Down Expand Up @@ -1637,6 +1663,7 @@ int cmd_clone(int argc,
string_list_clear(&option_not, 0);
string_list_clear(&option_config, 0);
string_list_clear(&server_options, 0);
strvec_clear(&alternates);

free(remote_name);
strbuf_release(&reflog_msg);
Expand Down
41 changes: 29 additions & 12 deletions builtin/commit-graph.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
#include "parse-options.h"
#include "commit-graph.h"
#include "odb.h"
#include "odb/source.h"
#include "odb/source-files.h"
#include "progress.h"
#include "replace-object.h"
#include "strbuf.h"
Expand Down Expand Up @@ -67,7 +69,7 @@ static int graph_verify(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
struct commit_graph *graph = NULL;
struct odb_source *source = NULL;
struct odb_files_dir *dir = NULL;
char *graph_name;
char *chain_name;
enum { OPENED_NONE, OPENED_GRAPH, OPENED_CHAIN } opened = OPENED_NONE;
Expand Down Expand Up @@ -102,9 +104,12 @@ static int graph_verify(int argc, const char **argv, const char *prefix,
if (opts.progress)
flags |= COMMIT_GRAPH_WRITE_PROGRESS;

source = odb_find_source_or_die(the_repository->objects, opts.obj_dir);
graph_name = get_commit_graph_filename(source);
chain_name = get_commit_graph_chain_filename(source);
dir = odb_source_files_find_dir(the_repository->objects, opts.obj_dir);
if (!dir)
die(_("could not find object directory matching %s"), opts.obj_dir);

graph_name = get_commit_graph_filename(dir->abspath);
chain_name = get_commit_graph_chain_filename(dir->abspath);
if (open_commit_graph(graph_name, &fd, &st))
opened = OPENED_GRAPH;
else if (errno != ENOENT)
Expand All @@ -122,7 +127,7 @@ static int graph_verify(int argc, const char **argv, const char *prefix,
if (opened == OPENED_NONE)
return 0;
else if (opened == OPENED_GRAPH)
graph = load_commit_graph_one_fd_st(source, fd, &st);
graph = load_commit_graph_one_fd_st(the_repository, dir->abspath, fd, &st);
else
graph = load_commit_graph_chain_fd_st(the_repository->objects, fd, &st,
&incomplete_chain);
Expand Down Expand Up @@ -225,7 +230,7 @@ static int graph_write(int argc, const char **argv, const char *prefix,
struct string_list pack_indexes = STRING_LIST_INIT_DUP;
struct strbuf buf = STRBUF_INIT;
struct oidset commits = OIDSET_INIT;
struct odb_source *source = NULL;
struct odb_files_dir *dir = NULL;
int result = 0;
enum commit_graph_write_flags flags = 0;
struct progress *progress = NULL;
Expand Down Expand Up @@ -293,18 +298,30 @@ static int graph_write(int argc, const char **argv, const char *prefix,
git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0))
flags |= COMMIT_GRAPH_WRITE_BLOOM_FILTERS;

source = odb_find_source_or_die(the_repository->objects, opts.obj_dir);
dir = odb_source_files_find_dir(the_repository->objects, opts.obj_dir);
if (!dir)
die(_("could not find object directory matching %s"), opts.obj_dir);

if (opts.reachable) {
if (write_commit_graph_reachable(source, flags, &write_opts))
if (write_commit_graph_reachable(the_repository, dir->abspath, flags, &write_opts))
result = 1;
goto cleanup;
}

if (opts.stdin_packs) {
while (strbuf_getline(&buf, stdin) != EOF)
string_list_append_nodup(&pack_indexes,
strbuf_detach(&buf, NULL));
struct strbuf packname = STRBUF_INIT;
size_t dirlen;

strbuf_addf(&packname, "%s/pack/", dir->abspath);
dirlen = packname.len;

while (strbuf_getline(&buf, stdin) != EOF) {
strbuf_setlen(&packname, dirlen);
strbuf_addbuf(&packname, &buf);
string_list_append(&pack_indexes, packname.buf);
}

strbuf_release(&packname);
} else if (opts.stdin_commits) {
oidset_init(&commits, 0);
if (opts.progress)
Expand All @@ -323,7 +340,7 @@ static int graph_write(int argc, const char **argv, const char *prefix,
stop_progress(&progress);
}

if (write_commit_graph(source,
if (write_commit_graph(the_repository, dir->abspath,
opts.stdin_packs ? &pack_indexes : NULL,
opts.stdin_commits ? &commits : NULL,
flags,
Expand Down
2 changes: 1 addition & 1 deletion builtin/commit.c
Original file line number Diff line number Diff line change
Expand Up @@ -2218,7 +2218,7 @@ int cmd_commit(int argc,
"new index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git restore --staged :/\" to recover."));

git_test_write_commit_graph_or_die(the_repository->objects->sources);
git_test_write_commit_graph_or_die(the_repository);

repo_rerere(the_repository, 0);
run_auto_maintenance(the_repository, quiet);
Expand Down
6 changes: 3 additions & 3 deletions builtin/count-objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,10 @@ static int count_cruft(const char *basename UNUSED, const char *path,
return 0;
}

static int print_alternate(struct odb_source *alternate, void *data UNUSED)
static int print_alternate(struct odb_files_dir *alternate, void *data UNUSED)
{
printf("alternate: ");
quote_c_style(alternate->path, NULL, stdout, 0);
quote_c_style(alternate->abspath, NULL, stdout, 0);
putchar('\n');
return 0;
}
Expand Down Expand Up @@ -118,7 +118,7 @@ int cmd_count_objects(int argc,
report_linked_checkout_garbage(the_repository);
}

for_each_loose_file_in_source(the_repository->objects->sources,
for_each_loose_file_in_source(the_repository->objects->source,
count_loose, count_cruft, NULL, NULL);

if (verbose) {
Expand Down
Loading
Loading