{"thread":{"id":"63902","subject":"[PATCH 0/9] commit-graph: remove reliance on global state","startedAt":"2025-08-04T08:17:23Z","lastAt":"2025-08-15T15:17:51Z","messageCount":69,"participants":["Patrick Steinhardt","Oswald Buddenhagen","Junio C Hamano","Taylor Blau","Derrick Stolee"],"isPatch":true,"patchVersion":1,"patchTotal":9},"messages":[{"id":"523389","messageId":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","threadId":"63902","inReplyTo":null,"subject":"[PATCH 0/9] commit-graph: remove reliance on global state","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-04T08:17:16Z","receivedAt":"2025-08-04T08:17:23Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Hi,\n\nthis patch series is another step on our long road towards not having\nglobal state. In addition to that, as commit-graphs are part of the\nobject database layer, this is also another step towards pluggable\nobject databases.\n\nThanks!\n\nPatrick\n\n---\nPatrick Steinhardt (9):\n      trace2: introduce function to trace unsigned integers\n      commit-graph: stop using signed integers to count bloom filters\n      commit-graph: fix type for some write options\n      commit-graph: fix sign comparison warnings\n      commit-graph: stop using `the_hash_algo` via macros\n      commit-graph: store the hash algorithm instead of its length\n      commit-graph: stop using `the_hash_algo`\n      commit-graph: stop using `the_repository`\n      commit-graph: stop passing in redundant repository\n\n builtin/commit-graph.c       |  13 +-\n builtin/commit.c             |   2 +-\n builtin/merge.c              |   2 +-\n commit-graph.c               | 366 +++++++++++++++++++++----------------------\n commit-graph.h               |  24 +--\n oss-fuzz/fuzz-commit-graph.c |   4 +-\n t/helper/test-read-graph.c   |   2 +-\n trace2.c                     |  14 ++\n trace2.h                     |   9 ++\n 9 files changed, 226 insertions(+), 210 deletions(-)\n\n\n---\nbase-commit: e813a0200a7121b97fec535f0d0b460b0a33356c\nchange-id: 20250717-b4-pks-commit-graph-wo-the-repository-1dc2cacbc8e3\n\n"},{"id":"523390","messageId":"20250804-b4-pks-commit-graph-wo-the-repository-v1-1-850d626eb2e8@pks.im","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","subject":"[PATCH 1/9] trace2: introduce function to trace unsigned integers","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-04T08:17:17Z","receivedAt":"2025-08-04T08:17:26Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"While we have `trace2_data_intmax()`, there is no equivalent function\nthat takes an unsigned integer. Introduce `trace2_data_uintmax()` to\nplug this gap.\n\nThis function will be used in a subsequent commit.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n trace2.c | 14 ++++++++++++++\n trace2.h |  9 +++++++++\n 2 files changed, 23 insertions(+)\n\ndiff --git a/trace2.c b/trace2.c\nindex c23c0a227b..a687944f7b 100644\n--- a/trace2.c\n+++ b/trace2.c\n@@ -948,6 +948,20 @@ void trace2_data_intmax_fl(const char *file, int line, const char *category,\n \tstrbuf_release(&buf_string);\n }\n \n+void trace2_data_uintmax_fl(const char *file, int line, const char *category,\n+\t\t\t    const struct repository *repo, const char *key,\n+\t\t\t    uintmax_t value)\n+{\n+\tstruct strbuf buf_string = STRBUF_INIT;\n+\n+\tif (!trace2_enabled)\n+\t\treturn;\n+\n+\tstrbuf_addf(&buf_string, \"%\" PRIuMAX, value);\n+\ttrace2_data_string_fl(file, line, category, repo, key, buf_string.buf);\n+\tstrbuf_release(&buf_string);\n+}\n+\n void trace2_data_json_fl(const char *file, int line, const char *category,\n \t\t\t const struct repository *repo, const char *key,\n \t\t\t const struct json_writer *value)\ndiff --git a/trace2.h b/trace2.h\nindex e4f23784e4..115c45a1eb 100644\n--- a/trace2.h\n+++ b/trace2.h\n@@ -463,6 +463,15 @@ void trace2_data_intmax_fl(const char *file, int line, const char *category,\n \ttrace2_data_intmax_fl(__FILE__, __LINE__, (category), (repo), (key), \\\n \t\t\t      (value))\n \n+void trace2_data_uintmax_fl(const char *file, int line, const char *category,\n+\t\t\t    const struct repository *repo, const char *key,\n+\t\t\t    uintmax_t value);\n+\n+#define trace2_data_uintmax(category, repo, key, value)                       \\\n+\ttrace2_data_uintmax_fl(__FILE__, __LINE__, (category), (repo), (key), \\\n+\t\t\t      (value))\n+\n+\n void trace2_data_json_fl(const char *file, int line, const char *category,\n \t\t\t const struct repository *repo, const char *key,\n \t\t\t const struct json_writer *jw);\n\n-- \n2.50.1.723.g3e08bea96f.dirty\n\n"},{"id":"523391","messageId":"20250804-b4-pks-commit-graph-wo-the-repository-v1-2-850d626eb2e8@pks.im","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","subject":"[PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-04T08:17:18Z","receivedAt":"2025-08-04T08:17:28Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"When writing a new commit graph we have a couple of counters that\nprovide statistics around what kind of bloom filters we have or have not\nwritten. These counters naturally count from zero and are only ever\nincremented, but they use a signed integer as type regardless.\n\nRefactor those fields to be of type `size_t` instead.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 30 +++++++++++++++---------------\n 1 file changed, 15 insertions(+), 15 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex bd7b6f5338..a7a1a761bc 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -1170,11 +1170,11 @@ struct write_commit_graph_context {\n \tsize_t total_bloom_filter_data_size;\n \tconst struct bloom_filter_settings *bloom_settings;\n \n-\tint count_bloom_filter_computed;\n-\tint count_bloom_filter_not_computed;\n-\tint count_bloom_filter_trunc_empty;\n-\tint count_bloom_filter_trunc_large;\n-\tint count_bloom_filter_upgraded;\n+\tsize_t count_bloom_filter_computed;\n+\tsize_t count_bloom_filter_not_computed;\n+\tsize_t count_bloom_filter_trunc_empty;\n+\tsize_t count_bloom_filter_trunc_large;\n+\tsize_t count_bloom_filter_upgraded;\n };\n \n static int write_graph_chunk_fanout(struct hashfile *f,\n@@ -1779,16 +1779,16 @@ void ensure_generations_valid(struct repository *r,\n \n static void trace2_bloom_filter_write_statistics(struct write_commit_graph_context *ctx)\n {\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-computed\",\n-\t\t\t   ctx->count_bloom_filter_computed);\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-not-computed\",\n-\t\t\t   ctx->count_bloom_filter_not_computed);\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-trunc-empty\",\n-\t\t\t   ctx->count_bloom_filter_trunc_empty);\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-trunc-large\",\n-\t\t\t   ctx->count_bloom_filter_trunc_large);\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-upgraded\",\n-\t\t\t   ctx->count_bloom_filter_upgraded);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-computed\",\n+\t\t\t    ctx->count_bloom_filter_computed);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-not-computed\",\n+\t\t\t    ctx->count_bloom_filter_not_computed);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-trunc-empty\",\n+\t\t\t    ctx->count_bloom_filter_trunc_empty);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-trunc-large\",\n+\t\t\t    ctx->count_bloom_filter_trunc_large);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-upgraded\",\n+\t\t\t    ctx->count_bloom_filter_upgraded);\n }\n \n static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n\n-- \n2.50.1.723.g3e08bea96f.dirty\n\n"},{"id":"523392","messageId":"20250804-b4-pks-commit-graph-wo-the-repository-v1-3-850d626eb2e8@pks.im","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","subject":"[PATCH 3/9] commit-graph: fix type for some write options","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-04T08:17:19Z","receivedAt":"2025-08-04T08:17:32Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The options \"max-commits\" and \"size-multiple\" are both supposed to be\npositive integers and are documented as such, but we use a signed\ninteger field to store them. This causes sign comparison warnings in\n`split_graph_merge_strategy()` because we end up comparing the option\nvalues with the observed number of commits.\n\nFix the issue by converting the fields to be unsigned and convert the\noptions to use `OPT_UNSIGNED()` accordingly. This macro has only been\nintroduced recently, which might explain why the option values were\nsigned in the first place.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit-graph.c | 4 ++--\n commit-graph.c         | 5 ++---\n commit-graph.h         | 4 ++--\n 3 files changed, 6 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/commit-graph.c b/builtin/commit-graph.c\nindex 25018a0b9d..145802afb7 100644\n--- a/builtin/commit-graph.c\n+++ b/builtin/commit-graph.c\n@@ -241,9 +241,9 @@ static int graph_write(int argc, const char **argv, const char *prefix,\n \t\t\tN_(\"allow writing an incremental commit-graph file\"),\n \t\t\tPARSE_OPT_OPTARG | PARSE_OPT_NONEG,\n \t\t\twrite_option_parse_split),\n-\t\tOPT_INTEGER(0, \"max-commits\", &write_opts.max_commits,\n+\t\tOPT_UNSIGNED(0, \"max-commits\", &write_opts.max_commits,\n \t\t\tN_(\"maximum number of commits in a non-base split commit-graph\")),\n-\t\tOPT_INTEGER(0, \"size-multiple\", &write_opts.size_multiple,\n+\t\tOPT_UNSIGNED(0, \"size-multiple\", &write_opts.size_multiple,\n \t\t\tN_(\"maximum ratio between two levels of a split commit-graph\")),\n \t\tOPT_EXPIRY_DATE(0, \"expire-time\", &write_opts.expire_time,\n \t\t\tN_(\"only expire files older than a given date-time\")),\ndiff --git a/commit-graph.c b/commit-graph.c\nindex a7a1a761bc..ad3f084dd4 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -2235,9 +2235,8 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)\n \tuint32_t num_commits;\n \tenum commit_graph_split_flags flags = COMMIT_GRAPH_SPLIT_UNSPECIFIED;\n \tuint32_t i;\n-\n-\tint max_commits = 0;\n-\tint size_mult = 2;\n+\tsize_t max_commits = 0;\n+\tsize_t size_mult = 2;\n \n \tif (ctx->opts) {\n \t\tmax_commits = ctx->opts->max_commits;\ndiff --git a/commit-graph.h b/commit-graph.h\nindex 78ab7b875b..b71cb55697 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -160,8 +160,8 @@ enum commit_graph_split_flags {\n };\n \n struct commit_graph_opts {\n-\tint size_multiple;\n-\tint max_commits;\n+\tsize_t size_multiple;\n+\tsize_t max_commits;\n \ttimestamp_t expire_time;\n \tenum commit_graph_split_flags split_flags;\n \tint max_new_filters;\n\n-- \n2.50.1.723.g3e08bea96f.dirty\n\n"},{"id":"523393","messageId":"20250804-b4-pks-commit-graph-wo-the-repository-v1-4-850d626eb2e8@pks.im","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","subject":"[PATCH 4/9] commit-graph: fix sign comparison warnings","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-04T08:17:20Z","receivedAt":"2025-08-04T08:17:35Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The \"commit-graph.c\" file has a bunch of sign comparison warnings:\n\n  - There are a bunch of variables that are declared as signed integers\n    even though they are used to count entities, like for example\n    `num_commit_graphs_before` and `num_commit_graphs_after`.\n\n  - There are several cases where we use signed loop variables to\n    iterate through an unsigned entity count.\n\n  - In `write_graph_chunk_base_1()` we count how many chunks we have\n    written in total. But while the value represents a positive\n    quantity, we still return a signed integer that we then later\n    compare with unsigned values.\n\n  - The bloom settings hash version is being assigned `-1` even though\n    it's an unsigned value. This is used to indicate an unspecified\n    value and relies on 1's complement.\n\nFix all of these cases by either using the proper variable type or by\nadding casts as required.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 54 +++++++++++++++++++++++++++---------------------------\n 1 file changed, 27 insertions(+), 27 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex ad3f084dd4..443177ffd3 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -1,5 +1,4 @@\n #define USE_THE_REPOSITORY_VARIABLE\n-#define DISABLE_SIGN_COMPARE_WARNINGS\n \n #include \"git-compat-util.h\"\n #include \"config.h\"\n@@ -569,7 +568,7 @@ static void validate_mixed_bloom_settings(struct commit_graph *g)\n static int add_graph_to_chain(struct commit_graph *g,\n \t\t\t      struct commit_graph *chain,\n \t\t\t      struct object_id *oids,\n-\t\t\t      int n)\n+\t\t\t      size_t n)\n {\n \tstruct commit_graph *cur_g = chain;\n \n@@ -622,7 +621,7 @@ int open_commit_graph_chain(const char *chain_file,\n \t\tclose(*fd);\n \t\treturn 0;\n \t}\n-\tif (st->st_size < the_hash_algo->hexsz) {\n+\tif (st->st_size < (ssize_t) the_hash_algo->hexsz) {\n \t\tclose(*fd);\n \t\tif (!st->st_size) {\n \t\t\t/* treat empty files the same as missing */\n@@ -643,15 +642,16 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \tstruct commit_graph *graph_chain = NULL;\n \tstruct strbuf line = STRBUF_INIT;\n \tstruct object_id *oids;\n-\tint i = 0, valid = 1, count;\n+\tint valid = 1;\n \tFILE *fp = xfdopen(fd, \"r\");\n+\tsize_t count;\n \n \tcount = st->st_size / (the_hash_algo->hexsz + 1);\n \tCALLOC_ARRAY(oids, count);\n \n \todb_prepare_alternates(r->objects);\n \n-\tfor (i = 0; i < count; i++) {\n+\tfor (size_t i = 0; i < count; i++) {\n \t\tstruct odb_source *source;\n \n \t\tif (strbuf_getline_lf(&line, fp) == EOF)\n@@ -1145,12 +1145,12 @@ struct write_commit_graph_context {\n \tint num_generation_data_overflows;\n \tunsigned long approx_nr_objects;\n \tstruct progress *progress;\n-\tint progress_done;\n+\tuint64_t progress_done;\n \tuint64_t progress_cnt;\n \n \tchar *base_graph_name;\n-\tint num_commit_graphs_before;\n-\tint num_commit_graphs_after;\n+\tsize_t num_commit_graphs_before;\n+\tsize_t num_commit_graphs_after;\n \tchar **commit_graph_filenames_before;\n \tchar **commit_graph_filenames_after;\n \tchar **commit_graph_hash_after;\n@@ -1181,7 +1181,7 @@ static int write_graph_chunk_fanout(struct hashfile *f,\n \t\t\t\t    void *data)\n {\n \tstruct write_commit_graph_context *ctx = data;\n-\tint i, count = 0;\n+\tsize_t i, count = 0;\n \tstruct commit **list = ctx->commits.list;\n \n \t/*\n@@ -1209,7 +1209,8 @@ static int write_graph_chunk_oids(struct hashfile *f,\n {\n \tstruct write_commit_graph_context *ctx = data;\n \tstruct commit **list = ctx->commits.list;\n-\tint count;\n+\tsize_t count;\n+\n \tfor (count = 0; count < ctx->commits.nr; count++, list++) {\n \t\tdisplay_progress(ctx->progress, ++ctx->progress_cnt);\n \t\thashwrite(f, (*list)->object.oid.hash, the_hash_algo->rawsz);\n@@ -1331,9 +1332,9 @@ static int write_graph_chunk_generation_data(struct hashfile *f,\n \t\t\t\t\t     void *data)\n {\n \tstruct write_commit_graph_context *ctx = data;\n-\tint i, num_generation_data_overflows = 0;\n+\tint num_generation_data_overflows = 0;\n \n-\tfor (i = 0; i < ctx->commits.nr; i++) {\n+\tfor (size_t i = 0; i < ctx->commits.nr; i++) {\n \t\tstruct commit *c = ctx->commits.list[i];\n \t\ttimestamp_t offset;\n \t\trepo_parse_commit(ctx->r, c);\n@@ -1355,8 +1356,8 @@ static int write_graph_chunk_generation_data_overflow(struct hashfile *f,\n \t\t\t\t\t\t      void *data)\n {\n \tstruct write_commit_graph_context *ctx = data;\n-\tint i;\n-\tfor (i = 0; i < ctx->commits.nr; i++) {\n+\n+\tfor (size_t i = 0; i < ctx->commits.nr; i++) {\n \t\tstruct commit *c = ctx->commits.list[i];\n \t\ttimestamp_t offset = commit_graph_data_at(c)->generation - c->date;\n \t\tdisplay_progress(ctx->progress, ++ctx->progress_cnt);\n@@ -1526,7 +1527,7 @@ static void add_missing_parents(struct write_commit_graph_context *ctx, struct c\n \n static void close_reachable(struct write_commit_graph_context *ctx)\n {\n-\tint i;\n+\tsize_t i;\n \tstruct commit *commit;\n \tenum commit_graph_split_flags flags = ctx->opts ?\n \t\tctx->opts->split_flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;\n@@ -1620,10 +1621,9 @@ static void compute_reachable_generation_numbers(\n \t\t\tstruct compute_generation_info *info,\n \t\t\tint generation_version)\n {\n-\tint i;\n \tstruct commit_list *list = NULL;\n \n-\tfor (i = 0; i < info->commits->nr; i++) {\n+\tfor (size_t i = 0; i < info->commits->nr; i++) {\n \t\tstruct commit *c = info->commits->list[i];\n \t\ttimestamp_t gen;\n \t\trepo_parse_commit(info->r, c);\n@@ -1714,7 +1714,7 @@ static void set_generation_v2(struct commit *c, timestamp_t t,\n \n static void compute_generation_numbers(struct write_commit_graph_context *ctx)\n {\n-\tint i;\n+\tsize_t i;\n \tstruct compute_generation_info info = {\n \t\t.r = ctx->r,\n \t\t.commits = &ctx->commits,\n@@ -1793,10 +1793,10 @@ static void trace2_bloom_filter_write_statistics(struct write_commit_graph_conte\n \n static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n {\n-\tint i;\n+\tsize_t i;\n \tstruct progress *progress = NULL;\n \tstruct commit **sorted_commits;\n-\tint max_new_filters;\n+\tsize_t max_new_filters;\n \n \tinit_bloom_filters();\n \n@@ -1814,7 +1814,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n \t\tQSORT(sorted_commits, ctx->commits.nr, commit_gen_cmp);\n \n \tmax_new_filters = ctx->opts && ctx->opts->max_new_filters >= 0 ?\n-\t\tctx->opts->max_new_filters : ctx->commits.nr;\n+\t\t(size_t) ctx->opts->max_new_filters : ctx->commits.nr;\n \n \tfor (i = 0; i < ctx->commits.nr; i++) {\n \t\tenum bloom_filter_computed computed = 0;\n@@ -2017,10 +2017,10 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx)\n \tstop_progress(&ctx->progress);\n }\n \n-static int write_graph_chunk_base_1(struct hashfile *f,\n-\t\t\t\t    struct commit_graph *g)\n+static size_t write_graph_chunk_base_1(struct hashfile *f,\n+\t\t\t\t       struct commit_graph *g)\n {\n-\tint num = 0;\n+\tsize_t num = 0;\n \n \tif (!g)\n \t\treturn 0;\n@@ -2034,7 +2034,7 @@ static int write_graph_chunk_base(struct hashfile *f,\n \t\t\t\t    void *data)\n {\n \tstruct write_commit_graph_context *ctx = data;\n-\tint num = write_graph_chunk_base_1(f, ctx->new_base_graph);\n+\tsize_t num = write_graph_chunk_base_1(f, ctx->new_base_graph);\n \n \tif (num != ctx->num_commit_graphs_after - 1) {\n \t\terror(_(\"failed to write correct number of base graph ids\"));\n@@ -2480,7 +2480,7 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)\n \t\tif (stat(path.buf, &st) < 0)\n \t\t\tcontinue;\n \n-\t\tif (st.st_mtime > expire_time)\n+\t\tif ((unsigned) st.st_mtime > expire_time)\n \t\t\tcontinue;\n \t\tif (path.len < 6 || strcmp(path.buf + path.len - 6, \".graph\"))\n \t\t\tcontinue;\n@@ -2576,7 +2576,7 @@ int write_commit_graph(struct odb_source *source,\n \t\t\tctx.changed_paths = 1;\n \n \t\t\t/* don't propagate the hash_version unless unspecified */\n-\t\t\tif (bloom_settings.hash_version == -1)\n+\t\t\tif (bloom_settings.hash_version == (unsigned) -1)\n \t\t\t\tbloom_settings.hash_version = g->bloom_filter_settings->hash_version;\n \t\t\tbloom_settings.bits_per_entry = g->bloom_filter_settings->bits_per_entry;\n \t\t\tbloom_settings.num_hashes = g->bloom_filter_settings->num_hashes;\n\n-- \n2.50.1.723.g3e08bea96f.dirty\n\n"},{"id":"523394","messageId":"20250804-b4-pks-commit-graph-wo-the-repository-v1-5-850d626eb2e8@pks.im","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","subject":"[PATCH 5/9] commit-graph: stop using `the_hash_algo` via macros","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-04T08:17:21Z","receivedAt":"2025-08-04T08:17:38Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have two macros `GRAPH_DATA_WIDTH` and `GRAPH_MIN_SIZE` that compute\nhash-dependent sizes. They do so by using the global `the_hash_algo`\nvariable though, which we want to get rid of over time.\n\nConvert these macros into functions that accept the hash algorithm as\ninput parameter. Adapt callers accordingly.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 25 ++++++++++++++++---------\n 1 file changed, 16 insertions(+), 9 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 443177ffd3..3c40f4a470 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -52,8 +52,6 @@ void git_test_write_commit_graph_or_die(void)\n #define GRAPH_CHUNKID_BLOOMDATA 0x42444154 /* \"BDAT\" */\n #define GRAPH_CHUNKID_BASE 0x42415345 /* \"BASE\" */\n \n-#define GRAPH_DATA_WIDTH (the_hash_algo->rawsz + 16)\n-\n #define GRAPH_VERSION_1 0x1\n #define GRAPH_VERSION GRAPH_VERSION_1\n \n@@ -65,8 +63,6 @@ void git_test_write_commit_graph_or_die(void)\n \n #define GRAPH_HEADER_SIZE 8\n #define GRAPH_FANOUT_SIZE (4 * 256)\n-#define GRAPH_MIN_SIZE (GRAPH_HEADER_SIZE + 4 * CHUNK_TOC_ENTRY_SIZE \\\n-\t\t\t+ GRAPH_FANOUT_SIZE + the_hash_algo->rawsz)\n \n #define CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW (1ULL << 31)\n \n@@ -79,6 +75,16 @@ define_commit_slab(topo_level_slab, uint32_t);\n define_commit_slab(commit_pos, int);\n static struct commit_pos commit_pos = COMMIT_SLAB_INIT(1, commit_pos);\n \n+static size_t graph_data_width(const struct git_hash_algo *algop)\n+{\n+\treturn algop->rawsz + 16;\n+}\n+\n+static size_t graph_min_size(const struct git_hash_algo *algop)\n+{\n+\treturn GRAPH_HEADER_SIZE + 4 * CHUNK_TOC_ENTRY_SIZE + GRAPH_FANOUT_SIZE + algop->rawsz;\n+}\n+\n static void set_commit_pos(struct repository *r, const struct object_id *oid)\n {\n \tstatic int32_t max_pos;\n@@ -257,7 +263,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \n \tgraph_size = xsize_t(st->st_size);\n \n-\tif (graph_size < GRAPH_MIN_SIZE) {\n+\tif (graph_size < graph_min_size(the_hash_algo)) {\n \t\tclose(fd);\n \t\terror(_(\"commit-graph file is too small\"));\n \t\treturn NULL;\n@@ -313,7 +319,7 @@ static int graph_read_commit_data(const unsigned char *chunk_start,\n \t\t\t\t  size_t chunk_size, void *data)\n {\n \tstruct commit_graph *g = data;\n-\tif (chunk_size / GRAPH_DATA_WIDTH != g->num_commits)\n+\tif (chunk_size / graph_data_width(the_hash_algo) != g->num_commits)\n \t\treturn error(_(\"commit-graph commit data chunk is wrong size\"));\n \tg->chunk_commit_data = chunk_start;\n \treturn 0;\n@@ -378,7 +384,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \tif (!graph_map)\n \t\treturn NULL;\n \n-\tif (graph_size < GRAPH_MIN_SIZE)\n+\tif (graph_size < graph_min_size(the_hash_algo))\n \t\treturn NULL;\n \n \tdata = (const unsigned char *)graph_map;\n@@ -900,7 +906,7 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \t\tdie(_(\"invalid commit position. commit-graph is likely corrupt\"));\n \n \tlex_index = pos - g->num_commits_in_base;\n-\tcommit_data = g->chunk_commit_data + st_mult(GRAPH_DATA_WIDTH, lex_index);\n+\tcommit_data = g->chunk_commit_data + st_mult(graph_data_width(the_hash_algo), lex_index);\n \n \tgraph_data = commit_graph_data_at(item);\n \tgraph_data->graph_pos = pos;\n@@ -1104,7 +1110,8 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\tg = g->base_graph;\n \n \tcommit_data = g->chunk_commit_data +\n-\t\t\tst_mult(GRAPH_DATA_WIDTH, graph_pos - g->num_commits_in_base);\n+\t\t\tst_mult(graph_data_width(the_hash_algo),\n+\t\t\t\tgraph_pos - g->num_commits_in_base);\n \n \toidread(&oid, commit_data, the_repository->hash_algo);\n \tset_commit_tree(c, lookup_tree(r, &oid));\n\n-- \n2.50.1.723.g3e08bea96f.dirty\n\n"},{"id":"523395","messageId":"20250804-b4-pks-commit-graph-wo-the-repository-v1-6-850d626eb2e8@pks.im","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","subject":"[PATCH 6/9] commit-graph: store the hash algorithm instead of its length","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-04T08:17:22Z","receivedAt":"2025-08-04T08:17:41Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The commit-graph stores the length of the hash algorithm it uses. In\nsubsequent commits we'll need to pass the whole hash algorithm around\nthough, which we currently don't have access to.\n\nRefactor the code so that we store the hash algorithm instead of only\nits size.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 36 ++++++++++++++++++------------------\n commit-graph.h |  2 +-\n 2 files changed, 19 insertions(+), 19 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 3c40f4a470..9c2278dd7a 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -310,7 +310,7 @@ static int graph_read_oid_lookup(const unsigned char *chunk_start,\n {\n \tstruct commit_graph *g = data;\n \tg->chunk_oid_lookup = chunk_start;\n-\tif (chunk_size / g->hash_len != g->num_commits)\n+\tif (chunk_size / g->hash_algo->rawsz != g->num_commits)\n \t\treturn error(_(\"commit-graph OID lookup chunk is the wrong size\"));\n \treturn 0;\n }\n@@ -412,7 +412,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \n \tgraph = alloc_commit_graph();\n \n-\tgraph->hash_len = the_hash_algo->rawsz;\n+\tgraph->hash_algo = the_hash_algo;\n \tgraph->num_chunks = *(unsigned char*)(data + 6);\n \tgraph->data = graph_map;\n \tgraph->data_len = graph_size;\n@@ -477,7 +477,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t\tFREE_AND_NULL(graph->bloom_filter_settings);\n \t}\n \n-\toidread(&graph->oid, graph->data + graph->data_len - graph->hash_len,\n+\toidread(&graph->oid, graph->data + graph->data_len - graph->hash_algo->rawsz,\n \t\tthe_repository->hash_algo);\n \n \tfree_chunkfile(cf);\n@@ -583,7 +583,7 @@ static int add_graph_to_chain(struct commit_graph *g,\n \t\treturn 0;\n \t}\n \n-\tif (g->chunk_base_graphs_size / g->hash_len < n) {\n+\tif (g->chunk_base_graphs_size / g->hash_algo->rawsz < n) {\n \t\twarning(_(\"commit-graph base graphs chunk is too small\"));\n \t\treturn 0;\n \t}\n@@ -593,7 +593,7 @@ static int add_graph_to_chain(struct commit_graph *g,\n \n \t\tif (!cur_g ||\n \t\t    !oideq(&oids[n], &cur_g->oid) ||\n-\t\t    !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_len, n),\n+\t\t    !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_algo->rawsz, n),\n \t\t\t    the_repository->hash_algo)) {\n \t\t\twarning(_(\"commit-graph chain does not match\"));\n \t\t\treturn 0;\n@@ -805,7 +805,7 @@ int generation_numbers_enabled(struct repository *r)\n \t\treturn 0;\n \n \tfirst_generation = get_be32(g->chunk_commit_data +\n-\t\t\t\t    g->hash_len + 8) >> 2;\n+\t\t\t\t    g->hash_algo->rawsz + 8) >> 2;\n \n \treturn !!first_generation;\n }\n@@ -849,7 +849,7 @@ void close_commit_graph(struct object_database *o)\n static int bsearch_graph(struct commit_graph *g, const struct object_id *oid, uint32_t *pos)\n {\n \treturn bsearch_hash(oid->hash, g->chunk_oid_fanout,\n-\t\t\t    g->chunk_oid_lookup, g->hash_len, pos);\n+\t\t\t    g->chunk_oid_lookup, g->hash_algo->rawsz, pos);\n }\n \n static void load_oid_from_graph(struct commit_graph *g,\n@@ -869,7 +869,7 @@ static void load_oid_from_graph(struct commit_graph *g,\n \n \tlex_index = pos - g->num_commits_in_base;\n \n-\toidread(oid, g->chunk_oid_lookup + st_mult(g->hash_len, lex_index),\n+\toidread(oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, lex_index),\n \t\tthe_repository->hash_algo);\n }\n \n@@ -911,8 +911,8 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \tgraph_data = commit_graph_data_at(item);\n \tgraph_data->graph_pos = pos;\n \n-\tdate_high = get_be32(commit_data + g->hash_len + 8) & 0x3;\n-\tdate_low = get_be32(commit_data + g->hash_len + 12);\n+\tdate_high = get_be32(commit_data + g->hash_algo->rawsz + 8) & 0x3;\n+\tdate_low = get_be32(commit_data + g->hash_algo->rawsz + 12);\n \titem->date = (timestamp_t)((date_high << 32) | date_low);\n \n \tif (g->read_generation_data) {\n@@ -930,10 +930,10 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \t\t} else\n \t\t\tgraph_data->generation = item->date + offset;\n \t} else\n-\t\tgraph_data->generation = get_be32(commit_data + g->hash_len + 8) >> 2;\n+\t\tgraph_data->generation = get_be32(commit_data + g->hash_algo->rawsz + 8) >> 2;\n \n \tif (g->topo_levels)\n-\t\t*topo_level_slab_at(g->topo_levels, item) = get_be32(commit_data + g->hash_len + 8) >> 2;\n+\t\t*topo_level_slab_at(g->topo_levels, item) = get_be32(commit_data + g->hash_algo->rawsz + 8) >> 2;\n }\n \n static inline void set_commit_tree(struct commit *c, struct tree *t)\n@@ -957,7 +957,7 @@ static int fill_commit_in_graph(struct repository *r,\n \tfill_commit_graph_info(item, g, pos);\n \n \tlex_index = pos - g->num_commits_in_base;\n-\tcommit_data = g->chunk_commit_data + st_mult(g->hash_len + 16, lex_index);\n+\tcommit_data = g->chunk_commit_data + st_mult(g->hash_algo->rawsz + 16, lex_index);\n \n \titem->object.parsed = 1;\n \n@@ -965,12 +965,12 @@ static int fill_commit_in_graph(struct repository *r,\n \n \tpptr = &item->parents;\n \n-\tedge_value = get_be32(commit_data + g->hash_len);\n+\tedge_value = get_be32(commit_data + g->hash_algo->rawsz);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n \tpptr = insert_parent_or_die(r, g, edge_value, pptr);\n \n-\tedge_value = get_be32(commit_data + g->hash_len + 4);\n+\tedge_value = get_be32(commit_data + g->hash_algo->rawsz + 4);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n \tif (!(edge_value & GRAPH_EXTRA_EDGES_NEEDED)) {\n@@ -2622,7 +2622,7 @@ int write_commit_graph(struct odb_source *source,\n \t\tstruct commit_graph *g = ctx.r->objects->commit_graph;\n \t\tfor (i = 0; i < g->num_commits; i++) {\n \t\t\tstruct object_id oid;\n-\t\t\toidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),\n+\t\t\toidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n \t\t\t\tthe_repository->hash_algo);\n \t\t\toid_array_append(&ctx.oids, &oid);\n \t\t}\n@@ -2753,7 +2753,7 @@ static int verify_one_commit_graph(struct repository *r,\n \tfor (i = 0; i < g->num_commits; i++) {\n \t\tstruct commit *graph_commit;\n \n-\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),\n+\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n \t\t\tthe_repository->hash_algo);\n \n \t\tif (i && oidcmp(&prev_oid, &cur_oid) >= 0)\n@@ -2798,7 +2798,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\ttimestamp_t generation;\n \n \t\tdisplay_progress(progress, ++(*seen));\n-\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),\n+\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n \t\t\tthe_repository->hash_algo);\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\ndiff --git a/commit-graph.h b/commit-graph.h\nindex b71cb55697..f20d28ff3a 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -84,7 +84,7 @@ struct commit_graph {\n \tconst unsigned char *data;\n \tsize_t data_len;\n \n-\tunsigned char hash_len;\n+\tconst struct git_hash_algo *hash_algo;\n \tunsigned char num_chunks;\n \tuint32_t num_commits;\n \tstruct object_id oid;\n\n-- \n2.50.1.723.g3e08bea96f.dirty\n\n"},{"id":"523396","messageId":"20250804-b4-pks-commit-graph-wo-the-repository-v1-7-850d626eb2e8@pks.im","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","subject":"[PATCH 7/9] commit-graph: stop using `the_hash_algo`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-04T08:17:23Z","receivedAt":"2025-08-04T08:17:44Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Stop using `the_hash_algo` as it implicitly relies on `the_repository`.\nInstead, we either use the hash algo provided via the context or, if\nthere is no such hash algo, we use `the_repository` explicitly. Such\nuses will be removed in subsequent commits.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit-graph.c       |  3 ++-\n commit-graph.c               | 40 +++++++++++++++++++++-------------------\n commit-graph.h               |  4 +++-\n oss-fuzz/fuzz-commit-graph.c |  4 +++-\n 4 files changed, 29 insertions(+), 22 deletions(-)\n\ndiff --git a/builtin/commit-graph.c b/builtin/commit-graph.c\nindex 145802afb79..680b03a83a8 100644\n--- a/builtin/commit-graph.c\n+++ b/builtin/commit-graph.c\n@@ -108,7 +108,8 @@ static int graph_verify(int argc, const char **argv, const char *prefix,\n \t\topened = OPENED_GRAPH;\n \telse if (errno != ENOENT)\n \t\tdie_errno(_(\"Could not open commit-graph '%s'\"), graph_name);\n-\telse if (open_commit_graph_chain(chain_name, &fd, &st))\n+\telse if (open_commit_graph_chain(chain_name, &fd, &st,\n+\t\t\t\t\t the_repository->hash_algo))\n \t\topened = OPENED_CHAIN;\n \telse if (errno != ENOENT)\n \t\tdie_errno(_(\"could not open commit-graph chain '%s'\"), chain_name);\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 9c2278dd7a1..b3feb6dfd77 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -263,7 +263,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \n \tgraph_size = xsize_t(st->st_size);\n \n-\tif (graph_size < graph_min_size(the_hash_algo)) {\n+\tif (graph_size < graph_min_size(r->hash_algo)) {\n \t\tclose(fd);\n \t\terror(_(\"commit-graph file is too small\"));\n \t\treturn NULL;\n@@ -271,7 +271,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \tgraph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);\n \tclose(fd);\n \tprepare_repo_settings(r);\n-\tret = parse_commit_graph(&r->settings, graph_map, graph_size);\n+\tret = parse_commit_graph(&r->settings, r->hash_algo, graph_map, graph_size);\n \n \tif (ret)\n \t\tret->odb_source = source;\n@@ -319,7 +319,7 @@ static int graph_read_commit_data(const unsigned char *chunk_start,\n \t\t\t\t  size_t chunk_size, void *data)\n {\n \tstruct commit_graph *g = data;\n-\tif (chunk_size / graph_data_width(the_hash_algo) != g->num_commits)\n+\tif (chunk_size / graph_data_width(g->hash_algo) != g->num_commits)\n \t\treturn error(_(\"commit-graph commit data chunk is wrong size\"));\n \tg->chunk_commit_data = chunk_start;\n \treturn 0;\n@@ -373,6 +373,7 @@ static int graph_read_bloom_data(const unsigned char *chunk_start,\n }\n \n struct commit_graph *parse_commit_graph(struct repo_settings *s,\n+\t\t\t\t\tconst struct git_hash_algo *hash_algo,\n \t\t\t\t\tvoid *graph_map, size_t graph_size)\n {\n \tconst unsigned char *data;\n@@ -384,7 +385,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \tif (!graph_map)\n \t\treturn NULL;\n \n-\tif (graph_size < graph_min_size(the_hash_algo))\n+\tif (graph_size < graph_min_size(hash_algo))\n \t\treturn NULL;\n \n \tdata = (const unsigned char *)graph_map;\n@@ -404,22 +405,22 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t}\n \n \thash_version = *(unsigned char*)(data + 5);\n-\tif (hash_version != oid_version(the_hash_algo)) {\n+\tif (hash_version != oid_version(hash_algo)) {\n \t\terror(_(\"commit-graph hash version %X does not match version %X\"),\n-\t\t      hash_version, oid_version(the_hash_algo));\n+\t\t      hash_version, oid_version(hash_algo));\n \t\treturn NULL;\n \t}\n \n \tgraph = alloc_commit_graph();\n \n-\tgraph->hash_algo = the_hash_algo;\n+\tgraph->hash_algo = hash_algo;\n \tgraph->num_chunks = *(unsigned char*)(data + 6);\n \tgraph->data = graph_map;\n \tgraph->data_len = graph_size;\n \n \tif (graph_size < GRAPH_HEADER_SIZE +\n \t\t\t (graph->num_chunks + 1) * CHUNK_TOC_ENTRY_SIZE +\n-\t\t\t GRAPH_FANOUT_SIZE + the_hash_algo->rawsz) {\n+\t\t\t GRAPH_FANOUT_SIZE + hash_algo->rawsz) {\n \t\terror(_(\"commit-graph file is too small to hold %u chunks\"),\n \t\t      graph->num_chunks);\n \t\tfree(graph);\n@@ -618,7 +619,8 @@ static int add_graph_to_chain(struct commit_graph *g,\n }\n \n int open_commit_graph_chain(const char *chain_file,\n-\t\t\t    int *fd, struct stat *st)\n+\t\t\t    int *fd, struct stat *st,\n+\t\t\t    const struct git_hash_algo *hash_algo)\n {\n \t*fd = git_open(chain_file);\n \tif (*fd < 0)\n@@ -627,7 +629,7 @@ int open_commit_graph_chain(const char *chain_file,\n \t\tclose(*fd);\n \t\treturn 0;\n \t}\n-\tif (st->st_size < (ssize_t) the_hash_algo->hexsz) {\n+\tif (st->st_size < (ssize_t) hash_algo->hexsz) {\n \t\tclose(*fd);\n \t\tif (!st->st_size) {\n \t\t\t/* treat empty files the same as missing */\n@@ -652,7 +654,7 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \tFILE *fp = xfdopen(fd, \"r\");\n \tsize_t count;\n \n-\tcount = st->st_size / (the_hash_algo->hexsz + 1);\n+\tcount = st->st_size / (r->hash_algo->hexsz + 1);\n \tCALLOC_ARRAY(oids, count);\n \n \todb_prepare_alternates(r->objects);\n@@ -714,7 +716,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,\n \tint fd;\n \tstruct commit_graph *g = NULL;\n \n-\tif (open_commit_graph_chain(chain_file, &fd, &st)) {\n+\tif (open_commit_graph_chain(chain_file, &fd, &st, r->hash_algo)) {\n \t\tint incomplete;\n \t\t/* ownership of fd is taken over by load function */\n \t\tg = load_commit_graph_chain_fd_st(r, fd, &st, &incomplete);\n@@ -906,7 +908,7 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \t\tdie(_(\"invalid commit position. commit-graph is likely corrupt\"));\n \n \tlex_index = pos - g->num_commits_in_base;\n-\tcommit_data = g->chunk_commit_data + st_mult(graph_data_width(the_hash_algo), lex_index);\n+\tcommit_data = g->chunk_commit_data + st_mult(graph_data_width(g->hash_algo), lex_index);\n \n \tgraph_data = commit_graph_data_at(item);\n \tgraph_data->graph_pos = pos;\n@@ -1110,7 +1112,7 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\tg = g->base_graph;\n \n \tcommit_data = g->chunk_commit_data +\n-\t\t\tst_mult(graph_data_width(the_hash_algo),\n+\t\t\tst_mult(graph_data_width(g->hash_algo),\n \t\t\t\tgraph_pos - g->num_commits_in_base);\n \n \toidread(&oid, commit_data, the_repository->hash_algo);\n@@ -1220,7 +1222,7 @@ static int write_graph_chunk_oids(struct hashfile *f,\n \n \tfor (count = 0; count < ctx->commits.nr; count++, list++) {\n \t\tdisplay_progress(ctx->progress, ++ctx->progress_cnt);\n-\t\thashwrite(f, (*list)->object.oid.hash, the_hash_algo->rawsz);\n+\t\thashwrite(f, (*list)->object.oid.hash, f->algop->rawsz);\n \t}\n \n \treturn 0;\n@@ -1251,7 +1253,7 @@ static int write_graph_chunk_data(struct hashfile *f,\n \t\t\tdie(_(\"unable to parse commit %s\"),\n \t\t\t\toid_to_hex(&(*list)->object.oid));\n \t\ttree = get_commit_tree_oid(*list);\n-\t\thashwrite(f, tree->hash, the_hash_algo->rawsz);\n+\t\thashwrite(f, tree->hash, ctx->r->hash_algo->rawsz);\n \n \t\tparent = (*list)->parents;\n \n@@ -2033,7 +2035,7 @@ static size_t write_graph_chunk_base_1(struct hashfile *f,\n \t\treturn 0;\n \n \tnum = write_graph_chunk_base_1(f, g->base_graph);\n-\thashwrite(f, g->oid.hash, the_hash_algo->rawsz);\n+\thashwrite(f, g->oid.hash, g->hash_algo->rawsz);\n \treturn num + 1;\n }\n \n@@ -2057,7 +2059,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \tstruct hashfile *f;\n \tstruct tempfile *graph_layer; /* when ctx->split is non-zero */\n \tstruct lock_file lk = LOCK_INIT;\n-\tconst unsigned hashsz = the_hash_algo->rawsz;\n+\tconst unsigned hashsz = ctx->r->hash_algo->rawsz;\n \tstruct strbuf progress_title = STRBUF_INIT;\n \tstruct chunkfile *cf;\n \tunsigned char file_hash[GIT_MAX_RAWSZ];\n@@ -2145,7 +2147,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \thashwrite_be32(f, GRAPH_SIGNATURE);\n \n \thashwrite_u8(f, GRAPH_VERSION);\n-\thashwrite_u8(f, oid_version(the_hash_algo));\n+\thashwrite_u8(f, oid_version(ctx->r->hash_algo));\n \thashwrite_u8(f, get_num_chunks(cf));\n \thashwrite_u8(f, ctx->num_commit_graphs_after - 1);\n \ndiff --git a/commit-graph.h b/commit-graph.h\nindex f20d28ff3a0..f26881849d6 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -32,7 +32,8 @@ struct string_list;\n char *get_commit_graph_filename(struct odb_source *source);\n char *get_commit_graph_chain_filename(struct odb_source *source);\n int open_commit_graph(const char *graph_file, int *fd, struct stat *st);\n-int open_commit_graph_chain(const char *chain_file, int *fd, struct stat *st);\n+int open_commit_graph_chain(const char *chain_file, int *fd, struct stat *st,\n+\t\t\t    const struct git_hash_algo *hash_algo);\n \n /*\n  * Given a commit struct, try to fill the commit struct info, including:\n@@ -129,6 +130,7 @@ struct repo_settings;\n  * prior to calling parse_commit_graph().\n  */\n struct commit_graph *parse_commit_graph(struct repo_settings *s,\n+\t\t\t\t\tconst struct git_hash_algo *hash_algo,\n \t\t\t\t\tvoid *graph_map, size_t graph_size);\n \n /*\ndiff --git a/oss-fuzz/fuzz-commit-graph.c b/oss-fuzz/fuzz-commit-graph.c\nindex fbb77fec197..879072f9d3c 100644\n--- a/oss-fuzz/fuzz-commit-graph.c\n+++ b/oss-fuzz/fuzz-commit-graph.c\n@@ -5,6 +5,7 @@\n #include \"repository.h\"\n \n struct commit_graph *parse_commit_graph(struct repo_settings *s,\n+\t\t\t\t\tconst struct git_hash_algo *hash_algo,\n \t\t\t\t\tvoid *graph_map, size_t graph_size);\n \n int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n@@ -24,7 +25,8 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n \trepo_set_hash_algo(the_repository, GIT_HASH_SHA1);\n \tthe_repository->settings.commit_graph_generation_version = 2;\n \tthe_repository->settings.commit_graph_changed_paths_version = 1;\n-\tg = parse_commit_graph(&the_repository->settings, (void *)data, size);\n+\tg = parse_commit_graph(&the_repository->settings, the_repository->hash_algo,\n+\t\t\t       (void *)data, size);\n \trepo_clear(the_repository);\n \tfree_commit_graph(g);\n \n\n-- \n2.50.1.723.g3e08bea96f.dirty\n\n"},{"id":"523397","messageId":"20250804-b4-pks-commit-graph-wo-the-repository-v1-8-850d626eb2e8@pks.im","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","subject":"[PATCH 8/9] commit-graph: stop using `the_repository`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-04T08:17:24Z","receivedAt":"2025-08-04T08:17:47Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"There's still a bunch of uses of `the_repository` in \"commit-graph.c\",\nwhich we want to stop using due to it being a global variable. Refactor\nthe code to stop using `the_repository` in favor of the repository\nprovided via the calling context.\n\nThis allows us to drop the `USE_THE_REPOSITORY_VARIABLE` macro.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit.c |  2 +-\n builtin/merge.c  |  2 +-\n commit-graph.c   | 79 ++++++++++++++++++++++++++++----------------------------\n commit-graph.h   |  2 +-\n 4 files changed, 43 insertions(+), 42 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 63e7158e98..8ca0aede48 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1933,7 +1933,7 @@ int cmd_commit(int argc,\n \t\t      \"new index file. Check that disk is not full and quota is\\n\"\n \t\t      \"not exceeded, and then \\\"git restore --staged :/\\\" to recover.\"));\n \n-\tgit_test_write_commit_graph_or_die();\n+\tgit_test_write_commit_graph_or_die(the_repository->objects->sources);\n \n \trepo_rerere(the_repository, 0);\n \trun_auto_maintenance(quiet);\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 18b22c0a26..263cb58471 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1862,7 +1862,7 @@ int cmd_merge(int argc,\n \tif (squash) {\n \t\tfinish(head_commit, remoteheads, NULL, NULL);\n \n-\t\tgit_test_write_commit_graph_or_die();\n+\t\tgit_test_write_commit_graph_or_die(the_repository->objects->sources);\n \t} else\n \t\twrite_merge_state(remoteheads);\n \ndiff --git a/commit-graph.c b/commit-graph.c\nindex b3feb6dfd7..7371db9702 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -1,5 +1,3 @@\n-#define USE_THE_REPOSITORY_VARIABLE\n-\n #include \"git-compat-util.h\"\n #include \"config.h\"\n #include \"csum-file.h\"\n@@ -27,7 +25,7 @@\n #include \"tree.h\"\n #include \"chunk-format.h\"\n \n-void git_test_write_commit_graph_or_die(void)\n+void git_test_write_commit_graph_or_die(struct odb_source *source)\n {\n \tint flags = 0;\n \tif (!git_env_bool(GIT_TEST_COMMIT_GRAPH, 0))\n@@ -36,8 +34,7 @@ void git_test_write_commit_graph_or_die(void)\n \tif (git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0))\n \t\tflags = COMMIT_GRAPH_WRITE_BLOOM_FILTERS;\n \n-\tif (write_commit_graph_reachable(the_repository->objects->sources,\n-\t\t\t\t\t flags, NULL))\n+\tif (write_commit_graph_reachable(source, flags, NULL))\n \t\tdie(\"failed to write commit-graph under GIT_TEST_COMMIT_GRAPH\");\n }\n \n@@ -479,7 +476,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t}\n \n \toidread(&graph->oid, graph->data + graph->data_len - graph->hash_algo->rawsz,\n-\t\tthe_repository->hash_algo);\n+\t\thash_algo);\n \n \tfree_chunkfile(cf);\n \treturn graph;\n@@ -595,7 +592,7 @@ static int add_graph_to_chain(struct commit_graph *g,\n \t\tif (!cur_g ||\n \t\t    !oideq(&oids[n], &cur_g->oid) ||\n \t\t    !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_algo->rawsz, n),\n-\t\t\t    the_repository->hash_algo)) {\n+\t\t\t    g->hash_algo)) {\n \t\t\twarning(_(\"commit-graph chain does not match\"));\n \t\t\treturn 0;\n \t\t}\n@@ -665,7 +662,7 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \t\tif (strbuf_getline_lf(&line, fp) == EOF)\n \t\t\tbreak;\n \n-\t\tif (get_oid_hex(line.buf, &oids[i])) {\n+\t\tif (get_oid_hex_algop(line.buf, &oids[i], r->hash_algo)) {\n \t\t\twarning(_(\"invalid commit-graph chain: line '%s' not a hash\"),\n \t\t\t\tline.buf);\n \t\t\tvalid = 0;\n@@ -751,7 +748,7 @@ static void prepare_commit_graph_one(struct repository *r,\n  * Return 1 if commit_graph is non-NULL, and 0 otherwise.\n  *\n  * On the first invocation, this function attempts to load the commit\n- * graph if the_repository is configured to have one.\n+ * graph if the repository is configured to have one.\n  */\n static int prepare_commit_graph(struct repository *r)\n {\n@@ -872,7 +869,7 @@ static void load_oid_from_graph(struct commit_graph *g,\n \tlex_index = pos - g->num_commits_in_base;\n \n \toidread(oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, lex_index),\n-\t\tthe_repository->hash_algo);\n+\t\tg->hash_algo);\n }\n \n static struct commit_list **insert_parent_or_die(struct repository *r,\n@@ -1115,7 +1112,7 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\t\tst_mult(graph_data_width(g->hash_algo),\n \t\t\t\tgraph_pos - g->num_commits_in_base);\n \n-\toidread(&oid, commit_data, the_repository->hash_algo);\n+\toidread(&oid, commit_data, g->hash_algo);\n \tset_commit_tree(c, lookup_tree(r, &oid));\n \n \treturn c->maybe_tree;\n@@ -1543,7 +1540,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Loading known commits in commit graph\"),\n \t\t\t\t\tctx->oids.nr);\n \tfor (i = 0; i < ctx->oids.nr; i++) {\n@@ -1561,7 +1558,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)\n \t */\n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Expanding reachable commits in commit graph\"),\n \t\t\t\t\t0);\n \tfor (i = 0; i < ctx->oids.nr; i++) {\n@@ -1582,7 +1579,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Clearing commit marks in commit graph\"),\n \t\t\t\t\tctx->oids.nr);\n \tfor (i = 0; i < ctx->oids.nr; i++) {\n@@ -1699,7 +1696,7 @@ static void compute_topological_levels(struct write_commit_graph_context *ctx)\n \tif (ctx->report_progress)\n \t\tinfo.progress = ctx->progress\n \t\t\t      = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Computing commit graph topological levels\"),\n \t\t\t\t\tctx->commits.nr);\n \n@@ -1734,7 +1731,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)\n \tif (ctx->report_progress)\n \t\tinfo.progress = ctx->progress\n \t\t\t      = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Computing commit graph generation numbers\"),\n \t\t\t\t\tctx->commits.nr);\n \n@@ -1811,7 +1808,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tprogress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\t_(\"Computing commit changed paths Bloom filters\"),\n \t\t\tctx->commits.nr);\n \n@@ -1857,6 +1854,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n }\n \n struct refs_cb_data {\n+\tstruct repository *repo;\n \tstruct oidset *commits;\n \tstruct progress *progress;\n };\n@@ -1869,9 +1867,9 @@ static int add_ref_to_set(const char *refname UNUSED,\n \tstruct object_id peeled;\n \tstruct refs_cb_data *data = (struct refs_cb_data *)cb_data;\n \n-\tif (!peel_iterated_oid(the_repository, oid, &peeled))\n+\tif (!peel_iterated_oid(data->repo, oid, &peeled))\n \t\toid = &peeled;\n-\tif (odb_read_object_info(the_repository->objects, oid, NULL) == OBJ_COMMIT)\n+\tif (odb_read_object_info(data->repo->objects, oid, NULL) == OBJ_COMMIT)\n \t\toidset_insert(data->commits, oid);\n \n \tdisplay_progress(data->progress, oidset_size(data->commits));\n@@ -1888,13 +1886,15 @@ int write_commit_graph_reachable(struct odb_source *source,\n \tint result;\n \n \tmemset(&data, 0, sizeof(data));\n+\tdata.repo = source->odb->repo;\n \tdata.commits = &commits;\n+\n \tif (flags & COMMIT_GRAPH_WRITE_PROGRESS)\n \t\tdata.progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tsource->odb->repo,\n \t\t\t_(\"Collecting referenced commits\"), 0);\n \n-\trefs_for_each_ref(get_main_ref_store(the_repository), add_ref_to_set,\n+\trefs_for_each_ref(get_main_ref_store(source->odb->repo), add_ref_to_set,\n \t\t\t  &data);\n \n \tstop_progress(&data.progress);\n@@ -1923,7 +1923,7 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx,\n \t\t\t       \"Finding commits for commit graph in %\"PRIuMAX\" packs\",\n \t\t\t       pack_indexes->nr),\n \t\t\t    (uintmax_t)pack_indexes->nr);\n-\t\tctx->progress = start_delayed_progress(the_repository,\n+\t\tctx->progress = start_delayed_progress(ctx->r,\n \t\t\t\t\t\t       progress_title.buf, 0);\n \t\tctx->progress_done = 0;\n \t}\n@@ -1977,7 +1977,7 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)\n {\n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\t_(\"Finding commits for commit graph among packed objects\"),\n \t\t\tctx->approx_nr_objects);\n \tfor_each_packed_object(ctx->r, add_packed_commits, ctx,\n@@ -1996,7 +1996,7 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx)\n \tctx->num_extra_edges = 0;\n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\t_(\"Finding extra edges in commit graph\"),\n \t\t\tctx->oids.nr);\n \toid_array_sort(&ctx->oids);\n@@ -2075,7 +2075,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\tctx->graph_name = get_commit_graph_filename(ctx->odb_source);\n \t}\n \n-\tif (safe_create_leading_directories(the_repository, ctx->graph_name)) {\n+\tif (safe_create_leading_directories(ctx->r, ctx->graph_name)) {\n \t\terror(_(\"unable to create leading directories of %s\"),\n \t\t\tctx->graph_name);\n \t\treturn -1;\n@@ -2094,18 +2094,18 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\t\treturn -1;\n \t\t}\n \n-\t\tif (adjust_shared_perm(the_repository, get_tempfile_path(graph_layer))) {\n+\t\tif (adjust_shared_perm(ctx->r, get_tempfile_path(graph_layer))) {\n \t\t\terror(_(\"unable to adjust shared permissions for '%s'\"),\n \t\t\t      get_tempfile_path(graph_layer));\n \t\t\treturn -1;\n \t\t}\n \n-\t\tf = hashfd(the_repository->hash_algo,\n+\t\tf = hashfd(ctx->r->hash_algo,\n \t\t\t   get_tempfile_fd(graph_layer), get_tempfile_path(graph_layer));\n \t} else {\n \t\thold_lock_file_for_update_mode(&lk, ctx->graph_name,\n \t\t\t\t\t       LOCK_DIE_ON_ERROR, 0444);\n-\t\tf = hashfd(the_repository->hash_algo,\n+\t\tf = hashfd(ctx->r->hash_algo,\n \t\t\t   get_lock_file_fd(&lk), get_lock_file_path(&lk));\n \t}\n \n@@ -2158,7 +2158,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\t\t       get_num_chunks(cf)),\n \t\t\t    get_num_chunks(cf));\n \t\tctx->progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\tprogress_title.buf,\n \t\t\tst_mult(get_num_chunks(cf), ctx->commits.nr));\n \t}\n@@ -2216,7 +2216,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\t}\n \n \t\tfree(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);\n-\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(hash_to_hex(file_hash));\n+\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] =\n+\t\t\txstrdup(hash_to_hex_algop(file_hash, ctx->r->hash_algo));\n \t\tfinal_graph_name = get_split_graph_filename(ctx->odb_source,\n \t\t\t\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);\n \t\tfree(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1]);\n@@ -2370,7 +2371,7 @@ static void sort_and_scan_merged_commits(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Scanning merged commits\"),\n \t\t\t\t\tctx->commits.nr);\n \n@@ -2415,7 +2416,7 @@ static void merge_commit_graphs(struct write_commit_graph_context *ctx)\n \t\tcurrent_graph_number--;\n \n \t\tif (ctx->report_progress)\n-\t\t\tctx->progress = start_delayed_progress(the_repository,\n+\t\t\tctx->progress = start_delayed_progress(ctx->r,\n \t\t\t\t\t\t\t       _(\"Merging commit-graph\"), 0);\n \n \t\tmerge_commit_graph(ctx, g);\n@@ -2518,7 +2519,7 @@ int write_commit_graph(struct odb_source *source,\n \t\t       enum commit_graph_write_flags flags,\n \t\t       const struct commit_graph_opts *opts)\n {\n-\tstruct repository *r = the_repository;\n+\tstruct repository *r = source->odb->repo;\n \tstruct write_commit_graph_context ctx = {\n \t\t.r = r,\n \t\t.odb_source = source,\n@@ -2618,14 +2619,14 @@ int write_commit_graph(struct odb_source *source,\n \t\t\treplace = ctx.opts->split_flags & COMMIT_GRAPH_SPLIT_REPLACE;\n \t}\n \n-\tctx.approx_nr_objects = repo_approximate_object_count(the_repository);\n+\tctx.approx_nr_objects = repo_approximate_object_count(r);\n \n \tif (ctx.append && ctx.r->objects->commit_graph) {\n \t\tstruct commit_graph *g = ctx.r->objects->commit_graph;\n \t\tfor (i = 0; i < g->num_commits; i++) {\n \t\t\tstruct object_id oid;\n \t\t\toidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n-\t\t\t\tthe_repository->hash_algo);\n+\t\t\t\tr->hash_algo);\n \t\t\toid_array_append(&ctx.oids, &oid);\n \t\t}\n \t}\n@@ -2733,7 +2734,7 @@ static void graph_report(const char *fmt, ...)\n \n static int commit_graph_checksum_valid(struct commit_graph *g)\n {\n-\treturn hashfile_checksum_valid(the_repository->hash_algo,\n+\treturn hashfile_checksum_valid(g->hash_algo,\n \t\t\t\t       g->data, g->data_len);\n }\n \n@@ -2756,7 +2757,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\tstruct commit *graph_commit;\n \n \t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n-\t\t\tthe_repository->hash_algo);\n+\t\t\tg->hash_algo);\n \n \t\tif (i && oidcmp(&prev_oid, &cur_oid) >= 0)\n \t\t\tgraph_report(_(\"commit-graph has incorrect OID order: %s then %s\"),\n@@ -2801,7 +2802,7 @@ static int verify_one_commit_graph(struct repository *r,\n \n \t\tdisplay_progress(progress, ++(*seen));\n \t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n-\t\t\tthe_repository->hash_algo);\n+\t\t\tg->hash_algo);\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\n \t\todb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r));\n@@ -2905,7 +2906,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n \t\tif (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW))\n \t\t\ttotal += g->num_commits_in_base;\n \n-\t\tprogress = start_progress(the_repository,\n+\t\tprogress = start_progress(r,\n \t\t\t\t\t  _(\"Verifying commits in commit graph\"),\n \t\t\t\t\t  total);\n \t}\ndiff --git a/commit-graph.h b/commit-graph.h\nindex f26881849d..24c1aca69e 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -21,7 +21,7 @@\n  * call this method oustide of a builtin, and only if you know what\n  * you are doing!\n  */\n-void git_test_write_commit_graph_or_die(void);\n+void git_test_write_commit_graph_or_die(struct odb_source *source);\n \n struct commit;\n struct bloom_filter_settings;\n\n-- \n2.50.1.723.g3e08bea96f.dirty\n\n"},{"id":"523398","messageId":"20250804-b4-pks-commit-graph-wo-the-repository-v1-9-850d626eb2e8@pks.im","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","subject":"[PATCH 9/9] commit-graph: stop passing in redundant repository","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-04T08:17:25Z","receivedAt":"2025-08-04T08:17:50Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Many of the commit-graph related functions take in both a repository and\nthe object database source (directly or via `struct commit_graph`) for\nwhich we are supposed to load such a commit-graph. In the best case this\ninformation is simply redundant as the source already contains a\nreference to its owning object database, which in turn has a reference\nto its repository. In the worst case this information could even\nmismatch when passing in a source that doesn't belong to the same\nrepository.\n\nRefactor the code so that we only pass in the object database source in\nthose cases.\n\nThere is one exception though, namely `load_commit_graph_chain_fd_st()`,\nwhich is responsible for loading a commit-graph chain. It is expected\nthat parts of the commit-graph chain aren't located in the same object\nsource as the chain file itself, but in a different one. Consequently,\nthis function doesn't work on the source level but on the database level\ninstead.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit-graph.c     |   6 +--\n commit-graph.c             | 123 +++++++++++++++++++--------------------------\n commit-graph.h             |  12 ++---\n t/helper/test-read-graph.c |   2 +-\n 4 files changed, 61 insertions(+), 82 deletions(-)\n\ndiff --git a/builtin/commit-graph.c b/builtin/commit-graph.c\nindex 680b03a83a..1b80993b2d 100644\n--- a/builtin/commit-graph.c\n+++ b/builtin/commit-graph.c\n@@ -121,15 +121,15 @@ static int graph_verify(int argc, const char **argv, const char *prefix,\n \tif (opened == OPENED_NONE)\n \t\treturn 0;\n \telse if (opened == OPENED_GRAPH)\n-\t\tgraph = load_commit_graph_one_fd_st(the_repository, fd, &st, source);\n+\t\tgraph = load_commit_graph_one_fd_st(source, fd, &st);\n \telse\n-\t\tgraph = load_commit_graph_chain_fd_st(the_repository, fd, &st,\n+\t\tgraph = load_commit_graph_chain_fd_st(the_repository->objects, fd, &st,\n \t\t\t\t\t\t      &incomplete_chain);\n \n \tif (!graph)\n \t\treturn 1;\n \n-\tret = verify_commit_graph(the_repository, graph, flags);\n+\tret = verify_commit_graph(graph, flags);\n \tfree_commit_graph(graph);\n \n \tif (incomplete_chain) {\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 7371db9702..308f27046c 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -250,9 +250,8 @@ int open_commit_graph(const char *graph_file, int *fd, struct stat *st)\n \treturn 1;\n }\n \n-struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n-\t\t\t\t\t\t int fd, struct stat *st,\n-\t\t\t\t\t\t struct odb_source *source)\n+struct commit_graph *load_commit_graph_one_fd_st(struct odb_source *source,\n+\t\t\t\t\t\t int fd, struct stat *st)\n {\n \tvoid *graph_map;\n \tsize_t graph_size;\n@@ -260,15 +259,16 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \n \tgraph_size = xsize_t(st->st_size);\n \n-\tif (graph_size < graph_min_size(r->hash_algo)) {\n+\tif (graph_size < graph_min_size(source->odb->repo->hash_algo)) {\n \t\tclose(fd);\n \t\terror(_(\"commit-graph file is too small\"));\n \t\treturn NULL;\n \t}\n \tgraph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);\n \tclose(fd);\n-\tprepare_repo_settings(r);\n-\tret = parse_commit_graph(&r->settings, r->hash_algo, graph_map, graph_size);\n+\tprepare_repo_settings(source->odb->repo);\n+\tret = parse_commit_graph(&source->odb->repo->settings, source->odb->repo->hash_algo,\n+\t\t\t\t graph_map, graph_size);\n \n \tif (ret)\n \t\tret->odb_source = source;\n@@ -488,11 +488,9 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \treturn NULL;\n }\n \n-static struct commit_graph *load_commit_graph_one(struct repository *r,\n-\t\t\t\t\t\t  const char *graph_file,\n-\t\t\t\t\t\t  struct odb_source *source)\n+static struct commit_graph *load_commit_graph_one(struct odb_source *source,\n+\t\t\t\t\t\t  const char *graph_file)\n {\n-\n \tstruct stat st;\n \tint fd;\n \tstruct commit_graph *g;\n@@ -501,19 +499,17 @@ static struct commit_graph *load_commit_graph_one(struct repository *r,\n \tif (!open_ok)\n \t\treturn NULL;\n \n-\tg = load_commit_graph_one_fd_st(r, fd, &st, source);\n-\n+\tg = load_commit_graph_one_fd_st(source, fd, &st);\n \tif (g)\n \t\tg->filename = xstrdup(graph_file);\n \n \treturn g;\n }\n \n-static struct commit_graph *load_commit_graph_v1(struct repository *r,\n-\t\t\t\t\t\t struct odb_source *source)\n+static struct commit_graph *load_commit_graph_v1(struct odb_source *source)\n {\n \tchar *graph_name = get_commit_graph_filename(source);\n-\tstruct commit_graph *g = load_commit_graph_one(r, graph_name, source);\n+\tstruct commit_graph *g = load_commit_graph_one(source, graph_name);\n \tfree(graph_name);\n \n \treturn g;\n@@ -640,7 +636,7 @@ int open_commit_graph_chain(const char *chain_file,\n \treturn 1;\n }\n \n-struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n+struct commit_graph *load_commit_graph_chain_fd_st(struct object_database *odb,\n \t\t\t\t\t\t   int fd, struct stat *st,\n \t\t\t\t\t\t   int *incomplete_chain)\n {\n@@ -651,10 +647,10 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \tFILE *fp = xfdopen(fd, \"r\");\n \tsize_t count;\n \n-\tcount = st->st_size / (r->hash_algo->hexsz + 1);\n+\tcount = st->st_size / (odb->repo->hash_algo->hexsz + 1);\n \tCALLOC_ARRAY(oids, count);\n \n-\todb_prepare_alternates(r->objects);\n+\todb_prepare_alternates(odb);\n \n \tfor (size_t i = 0; i < count; i++) {\n \t\tstruct odb_source *source;\n@@ -662,7 +658,7 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \t\tif (strbuf_getline_lf(&line, fp) == EOF)\n \t\t\tbreak;\n \n-\t\tif (get_oid_hex_algop(line.buf, &oids[i], r->hash_algo)) {\n+\t\tif (get_oid_hex_algop(line.buf, &oids[i], odb->repo->hash_algo)) {\n \t\t\twarning(_(\"invalid commit-graph chain: line '%s' not a hash\"),\n \t\t\t\tline.buf);\n \t\t\tvalid = 0;\n@@ -670,9 +666,9 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \t\t}\n \n \t\tvalid = 0;\n-\t\tfor (source = r->objects->sources; source; source = source->next) {\n+\t\tfor (source = odb->sources; source; source = source->next) {\n \t\t\tchar *graph_name = get_split_graph_filename(source, line.buf);\n-\t\t\tstruct commit_graph *g = load_commit_graph_one(r, graph_name, source);\n+\t\t\tstruct commit_graph *g = load_commit_graph_one(source, graph_name);\n \n \t\t\tfree(graph_name);\n \n@@ -705,45 +701,33 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \treturn graph_chain;\n }\n \n-static struct commit_graph *load_commit_graph_chain(struct repository *r,\n-\t\t\t\t\t\t    struct odb_source *source)\n+static struct commit_graph *load_commit_graph_chain(struct odb_source *source)\n {\n \tchar *chain_file = get_commit_graph_chain_filename(source);\n \tstruct stat st;\n \tint fd;\n \tstruct commit_graph *g = NULL;\n \n-\tif (open_commit_graph_chain(chain_file, &fd, &st, r->hash_algo)) {\n+\tif (open_commit_graph_chain(chain_file, &fd, &st, source->odb->repo->hash_algo)) {\n \t\tint incomplete;\n \t\t/* ownership of fd is taken over by load function */\n-\t\tg = load_commit_graph_chain_fd_st(r, fd, &st, &incomplete);\n+\t\tg = load_commit_graph_chain_fd_st(source->odb, fd, &st, &incomplete);\n \t}\n \n \tfree(chain_file);\n \treturn g;\n }\n \n-struct commit_graph *read_commit_graph_one(struct repository *r,\n-\t\t\t\t\t   struct odb_source *source)\n+struct commit_graph *read_commit_graph_one(struct odb_source *source)\n {\n-\tstruct commit_graph *g = load_commit_graph_v1(r, source);\n+\tstruct commit_graph *g = load_commit_graph_v1(source);\n \n \tif (!g)\n-\t\tg = load_commit_graph_chain(r, source);\n+\t\tg = load_commit_graph_chain(source);\n \n \treturn g;\n }\n \n-static void prepare_commit_graph_one(struct repository *r,\n-\t\t\t\t     struct odb_source *source)\n-{\n-\n-\tif (r->objects->commit_graph)\n-\t\treturn;\n-\n-\tr->objects->commit_graph = read_commit_graph_one(r, source);\n-}\n-\n /*\n  * Return 1 if commit_graph is non-NULL, and 0 otherwise.\n  *\n@@ -784,10 +768,12 @@ static int prepare_commit_graph(struct repository *r)\n \t\treturn 0;\n \n \todb_prepare_alternates(r->objects);\n-\tfor (source = r->objects->sources;\n-\t     !r->objects->commit_graph && source;\n-\t     source = source->next)\n-\t\tprepare_commit_graph_one(r, source);\n+\tfor (source = r->objects->sources; source; source = source->next) {\n+\t\tr->objects->commit_graph = read_commit_graph_one(source);\n+\t\tif (r->objects->commit_graph)\n+\t\t\tbreak;\n+\t}\n+\n \treturn !!r->objects->commit_graph;\n }\n \n@@ -872,8 +858,7 @@ static void load_oid_from_graph(struct commit_graph *g,\n \t\tg->hash_algo);\n }\n \n-static struct commit_list **insert_parent_or_die(struct repository *r,\n-\t\t\t\t\t\t struct commit_graph *g,\n+static struct commit_list **insert_parent_or_die(struct commit_graph *g,\n \t\t\t\t\t\t uint32_t pos,\n \t\t\t\t\t\t struct commit_list **pptr)\n {\n@@ -884,7 +869,7 @@ static struct commit_list **insert_parent_or_die(struct repository *r,\n \t\tdie(\"invalid parent position %\"PRIu32, pos);\n \n \tload_oid_from_graph(g, pos, &oid);\n-\tc = lookup_commit(r, &oid);\n+\tc = lookup_commit(g->odb_source->odb->repo, &oid);\n \tif (!c)\n \t\tdie(_(\"could not find commit %s\"), oid_to_hex(&oid));\n \tcommit_graph_data_at(c)->graph_pos = pos;\n@@ -940,8 +925,7 @@ static inline void set_commit_tree(struct commit *c, struct tree *t)\n \tc->maybe_tree = t;\n }\n \n-static int fill_commit_in_graph(struct repository *r,\n-\t\t\t\tstruct commit *item,\n+static int fill_commit_in_graph(struct commit *item,\n \t\t\t\tstruct commit_graph *g, uint32_t pos)\n {\n \tuint32_t edge_value;\n@@ -967,13 +951,13 @@ static int fill_commit_in_graph(struct repository *r,\n \tedge_value = get_be32(commit_data + g->hash_algo->rawsz);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n-\tpptr = insert_parent_or_die(r, g, edge_value, pptr);\n+\tpptr = insert_parent_or_die(g, edge_value, pptr);\n \n \tedge_value = get_be32(commit_data + g->hash_algo->rawsz + 4);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n \tif (!(edge_value & GRAPH_EXTRA_EDGES_NEEDED)) {\n-\t\tpptr = insert_parent_or_die(r, g, edge_value, pptr);\n+\t\tpptr = insert_parent_or_die(g, edge_value, pptr);\n \t\treturn 1;\n \t}\n \n@@ -988,7 +972,7 @@ static int fill_commit_in_graph(struct repository *r,\n \t\t}\n \t\tedge_value = get_be32(g->chunk_extra_edges +\n \t\t\t\t      sizeof(uint32_t) * parent_data_pos);\n-\t\tpptr = insert_parent_or_die(r, g,\n+\t\tpptr = insert_parent_or_die(g,\n \t\t\t\t\t    edge_value & GRAPH_EDGE_LAST_MASK,\n \t\t\t\t\t    pptr);\n \t\tparent_data_pos++;\n@@ -1054,14 +1038,13 @@ struct commit *lookup_commit_in_graph(struct repository *repo, const struct obje\n \tif (commit->object.parsed)\n \t\treturn commit;\n \n-\tif (!fill_commit_in_graph(repo, commit, repo->objects->commit_graph, pos))\n+\tif (!fill_commit_in_graph(commit, repo->objects->commit_graph, pos))\n \t\treturn NULL;\n \n \treturn commit;\n }\n \n-static int parse_commit_in_graph_one(struct repository *r,\n-\t\t\t\t     struct commit_graph *g,\n+static int parse_commit_in_graph_one(struct commit_graph *g,\n \t\t\t\t     struct commit *item)\n {\n \tuint32_t pos;\n@@ -1070,7 +1053,7 @@ static int parse_commit_in_graph_one(struct repository *r,\n \t\treturn 1;\n \n \tif (find_commit_pos_in_graph(item, g, &pos))\n-\t\treturn fill_commit_in_graph(r, item, g, pos);\n+\t\treturn fill_commit_in_graph(item, g, pos);\n \n \treturn 0;\n }\n@@ -1087,7 +1070,7 @@ int parse_commit_in_graph(struct repository *r, struct commit *item)\n \n \tif (!prepare_commit_graph(r))\n \t\treturn 0;\n-\treturn parse_commit_in_graph_one(r, r->objects->commit_graph, item);\n+\treturn parse_commit_in_graph_one(r->objects->commit_graph, item);\n }\n \n void load_commit_graph_info(struct repository *r, struct commit *item)\n@@ -1097,8 +1080,7 @@ void load_commit_graph_info(struct repository *r, struct commit *item)\n \t\tfill_commit_graph_info(item, r->objects->commit_graph, pos);\n }\n \n-static struct tree *load_tree_for_commit(struct repository *r,\n-\t\t\t\t\t struct commit_graph *g,\n+static struct tree *load_tree_for_commit(struct commit_graph *g,\n \t\t\t\t\t struct commit *c)\n {\n \tstruct object_id oid;\n@@ -1113,13 +1095,12 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\t\t\tgraph_pos - g->num_commits_in_base);\n \n \toidread(&oid, commit_data, g->hash_algo);\n-\tset_commit_tree(c, lookup_tree(r, &oid));\n+\tset_commit_tree(c, lookup_tree(g->odb_source->odb->repo, &oid));\n \n \treturn c->maybe_tree;\n }\n \n-static struct tree *get_commit_tree_in_graph_one(struct repository *r,\n-\t\t\t\t\t\t struct commit_graph *g,\n+static struct tree *get_commit_tree_in_graph_one(struct commit_graph *g,\n \t\t\t\t\t\t const struct commit *c)\n {\n \tif (c->maybe_tree)\n@@ -1127,12 +1108,12 @@ static struct tree *get_commit_tree_in_graph_one(struct repository *r,\n \tif (commit_graph_position(c) == COMMIT_NOT_FROM_GRAPH)\n \t\tBUG(\"get_commit_tree_in_graph_one called from non-commit-graph commit\");\n \n-\treturn load_tree_for_commit(r, g, (struct commit *)c);\n+\treturn load_tree_for_commit(g, (struct commit *)c);\n }\n \n struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit *c)\n {\n-\treturn get_commit_tree_in_graph_one(r, r->objects->commit_graph, c);\n+\treturn get_commit_tree_in_graph_one(r->objects->commit_graph, c);\n }\n \n struct packed_commit_list {\n@@ -2738,11 +2719,11 @@ static int commit_graph_checksum_valid(struct commit_graph *g)\n \t\t\t\t       g->data, g->data_len);\n }\n \n-static int verify_one_commit_graph(struct repository *r,\n-\t\t\t\t   struct commit_graph *g,\n+static int verify_one_commit_graph(struct commit_graph *g,\n \t\t\t\t   struct progress *progress,\n \t\t\t\t   uint64_t *seen)\n {\n+\tstruct repository *r = g->odb_source->odb->repo;\n \tuint32_t i, cur_fanout_pos = 0;\n \tstruct object_id prev_oid, cur_oid;\n \tstruct commit *seen_gen_zero = NULL;\n@@ -2776,7 +2757,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\t}\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\n-\t\tif (!parse_commit_in_graph_one(r, g, graph_commit))\n+\t\tif (!parse_commit_in_graph_one(g, graph_commit))\n \t\t\tgraph_report(_(\"failed to parse commit %s from commit-graph\"),\n \t\t\t\t     oid_to_hex(&cur_oid));\n \t}\n@@ -2812,7 +2793,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\t\tcontinue;\n \t\t}\n \n-\t\tif (!oideq(&get_commit_tree_in_graph_one(r, g, graph_commit)->object.oid,\n+\t\tif (!oideq(&get_commit_tree_in_graph_one(g, graph_commit)->object.oid,\n \t\t\t   get_commit_tree_oid(odb_commit)))\n \t\t\tgraph_report(_(\"root tree OID for commit %s in commit-graph is %s != %s\"),\n \t\t\t\t     oid_to_hex(&cur_oid),\n@@ -2830,7 +2811,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\t\t}\n \n \t\t\t/* parse parent in case it is in a base graph */\n-\t\t\tparse_commit_in_graph_one(r, g, graph_parents->item);\n+\t\t\tparse_commit_in_graph_one(g, graph_parents->item);\n \n \t\t\tif (!oideq(&graph_parents->item->object.oid, &odb_parents->item->object.oid))\n \t\t\t\tgraph_report(_(\"commit-graph parent for %s is %s != %s\"),\n@@ -2890,7 +2871,7 @@ static int verify_one_commit_graph(struct repository *r,\n \treturn verify_commit_graph_error;\n }\n \n-int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n+int verify_commit_graph(struct commit_graph *g, int flags)\n {\n \tstruct progress *progress = NULL;\n \tint local_error = 0;\n@@ -2906,13 +2887,13 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n \t\tif (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW))\n \t\t\ttotal += g->num_commits_in_base;\n \n-\t\tprogress = start_progress(r,\n+\t\tprogress = start_progress(g->odb_source->odb->repo,\n \t\t\t\t\t  _(\"Verifying commits in commit graph\"),\n \t\t\t\t\t  total);\n \t}\n \n \tfor (; g; g = g->base_graph) {\n-\t\tlocal_error |= verify_one_commit_graph(r, g, progress, &seen);\n+\t\tlocal_error |= verify_one_commit_graph(g, progress, &seen);\n \t\tif (flags & COMMIT_GRAPH_VERIFY_SHALLOW)\n \t\t\tbreak;\n \t}\ndiff --git a/commit-graph.h b/commit-graph.h\nindex 24c1aca69e..c7970be661 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -114,14 +114,12 @@ struct commit_graph {\n \tstruct bloom_filter_settings *bloom_filter_settings;\n };\n \n-struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n-\t\t\t\t\t\t int fd, struct stat *st,\n-\t\t\t\t\t\t struct odb_source *source);\n-struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n+struct commit_graph *load_commit_graph_one_fd_st(struct odb_source *source,\n+\t\t\t\t\t\t int fd, struct stat *st);\n+struct commit_graph *load_commit_graph_chain_fd_st(struct object_database *odb,\n \t\t\t\t\t\t   int fd, struct stat *st,\n \t\t\t\t\t\t   int *incomplete_chain);\n-struct commit_graph *read_commit_graph_one(struct repository *r,\n-\t\t\t\t\t   struct odb_source *source);\n+struct commit_graph *read_commit_graph_one(struct odb_source *source);\n \n struct repo_settings;\n \n@@ -186,7 +184,7 @@ int write_commit_graph(struct odb_source *source,\n \n #define COMMIT_GRAPH_VERIFY_SHALLOW\t(1 << 0)\n \n-int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags);\n+int verify_commit_graph(struct commit_graph *g, int flags);\n \n void close_commit_graph(struct object_database *);\n void free_commit_graph(struct commit_graph *);\ndiff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c\nindex ef5339bbee..6a5f64e473 100644\n--- a/t/helper/test-read-graph.c\n+++ b/t/helper/test-read-graph.c\n@@ -81,7 +81,7 @@ int cmd__read_graph(int argc, const char **argv)\n \n \tprepare_repo_settings(the_repository);\n \n-\tgraph = read_commit_graph_one(the_repository, source);\n+\tgraph = read_commit_graph_one(source);\n \tif (!graph) {\n \t\tret = 1;\n \t\tgoto done;\n\n-- \n2.50.1.723.g3e08bea96f.dirty\n\n"},{"id":"523401","messageId":"aJB5uKFdGybf-IbN@ugly","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-2-850d626eb2e8@pks.im","subject":"Re: [PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Oswald Buddenhagen","fromEmail":"oswald.buddenhagen@gmx.de","sentAt":"2025-08-04T09:13:28Z","receivedAt":"2025-08-04T09:13:30Z","isPatch":true,"sender":{"key":"oswald.buddenhagen@gmx.de","avatar":"https://avatars.githubusercontent.com/u/812380?v=4"},"body":"On Mon, Aug 04, 2025 at 10:17:18AM +0200, Patrick Steinhardt wrote:\n>When writing a new commit graph we have a couple of counters that\n>provide statistics around what kind of bloom filters we have or have not\n>written. These counters naturally count from zero and are only ever\n>incremented, but they use a signed integer as type regardless.\n>\n>Refactor those fields to be of type `size_t` instead.\n>\nmind elaborating on that choice?\nit feels like abuse at the semantic level, and it increases the data \nsize on lp64 platforms. is it even compatible with OPT_UNSIGNED (in \nlater commits)? that would be unexpected ...\n"},{"id":"523433","messageId":"aJCW7aYqJB20LDNg@pks.im","threadId":"63902","inReplyTo":"aJB5uKFdGybf-IbN@ugly","subject":"Re: [PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-04T11:18:05Z","receivedAt":"2025-08-04T11:18:12Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Mon, Aug 04, 2025 at 11:13:28AM +0200, Oswald Buddenhagen wrote:\n> On Mon, Aug 04, 2025 at 10:17:18AM +0200, Patrick Steinhardt wrote:\n> > When writing a new commit graph we have a couple of counters that\n> > provide statistics around what kind of bloom filters we have or have not\n> > written. These counters naturally count from zero and are only ever\n> > incremented, but they use a signed integer as type regardless.\n> > \n> > Refactor those fields to be of type `size_t` instead.\n> > \n> mind elaborating on that choice?\n\nWe tend to use `size_t` when counting stuff.\n\n> it feels like abuse at the semantic level, and it increases the data size on\n> lp64 platforms. is it even compatible with OPT_UNSIGNED (in later commits)?\n> that would be unexpected ...\n\nYes, it is, starting with my 2bc5414c41 (Merge branch\n'ps/parse-options-integers', 2025-04-24). Regarding the data size I\ndon't really think that matters much. It's not like we have hundreds of\nthousands of commit graphs in-memory at any point in time.\n\nPatrick\n"},{"id":"523473","messageId":"xmqq5xf35429.fsf@gitster.g","threadId":"63902","inReplyTo":"aJCW7aYqJB20LDNg@pks.im","subject":"Re: [PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-08-04T18:34:22Z","receivedAt":"2025-08-04T18:34:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> On Mon, Aug 04, 2025 at 11:13:28AM +0200, Oswald Buddenhagen wrote:\n>> On Mon, Aug 04, 2025 at 10:17:18AM +0200, Patrick Steinhardt wrote:\n>> > When writing a new commit graph we have a couple of counters that\n>> > provide statistics around what kind of bloom filters we have or have not\n>> > written. These counters naturally count from zero and are only ever\n>> > incremented, but they use a signed integer as type regardless.\n>> > \n>> > Refactor those fields to be of type `size_t` instead.\n>> > \n>> mind elaborating on that choice?\n>\n> We tend to use `size_t` when counting stuff.\n\nAnd I would have to say that it is wrong and we need to wean\nourselves from such a superstition.  Unless you are measuring how\nbig a memory block you ask from the allocator, the platform natural\ninteger is often the right type to do the counting.\n\nEach of your \"stuff\" may weigh N megabytes in core, and if you have\nM of them, you may have to ask (N*2**20)*M bytes of memory from the\nallocator.  Your (N*2**20)*M must fit size_t _and_ you must compute\nit without overflowing or wrapping around.\n\nNone of the above mean you have to express N in size_t, though.\nAnd more importantly, nobody gives you any extra guarantee that you\nwould compute the result correctly if you used size_t.  You can write\nthe right code with platform natural integer, and you have to take\nthe same care (e.g. by using st_mult()) to catch integer overflows\neven if you used size_t.\n\n> ... Regarding the data size I\n> don't really think that matters much. It's not like we have hundreds of\n> thousands of commit graphs in-memory at any point in time.\n\nAren't you saying that a platform natural integer is a much better\nfit?\n\nAs to signedness, it sometimes is better for a struct member that is\nused to record the number of \"stuff\" you have to be a signed integer\nthat is initialized to -1 to signal \"we haven't counted so we do not\nyet know how many there are\".  So\n\n    These counters naturally count from zero and are only ever\n    incremented.\n\nis not always a valid excuse to insist that such a variable must be\nunsigned.\n\nIn short, not all but much of the recent \"use size_t\" topics are\nmisguided, and -Wsign-compare is usually a wrong thing to rely on.\n"},{"id":"523482","messageId":"aJEnM0IOrgwizw2Y@nand.local","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-1-850d626eb2e8@pks.im","subject":"Re: [PATCH 1/9] trace2: introduce function to trace unsigned integers","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2025-08-04T21:33:39Z","receivedAt":"2025-08-04T21:33:42Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Mon, Aug 04, 2025 at 10:17:17AM +0200, Patrick Steinhardt wrote:\n> While we have `trace2_data_intmax()`, there is no equivalent function\n> that takes an unsigned integer. Introduce `trace2_data_uintmax()` to\n> plug this gap.\n>\n> This function will be used in a subsequent commit.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  trace2.c | 14 ++++++++++++++\n>  trace2.h |  9 +++++++++\n>  2 files changed, 23 insertions(+)\n>\n> diff --git a/trace2.c b/trace2.c\n> index c23c0a227b..a687944f7b 100644\n> --- a/trace2.c\n> +++ b/trace2.c\n> @@ -948,6 +948,20 @@ void trace2_data_intmax_fl(const char *file, int line, const char *category,\n>  \tstrbuf_release(&buf_string);\n>  }\n>\n> +void trace2_data_uintmax_fl(const char *file, int line, const char *category,\n> +\t\t\t    const struct repository *repo, const char *key,\n> +\t\t\t    uintmax_t value)\n> +{\n> +\tstruct strbuf buf_string = STRBUF_INIT;\n> +\n> +\tif (!trace2_enabled)\n> +\t\treturn;\n> +\n> +\tstrbuf_addf(&buf_string, \"%\" PRIuMAX, value);\n> +\ttrace2_data_string_fl(file, line, category, repo, key, buf_string.buf);\n> +\tstrbuf_release(&buf_string);\n> +}\n> +\n\nLooks like a faithful copy of its signed counterpart above, which is\ngood. We *could* use a macro for this, but I don't think we *should*\n;-).\n\nThanks,\nTaylor\n"},{"id":"523483","messageId":"aJEpU0VUav17beOt@nand.local","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-2-850d626eb2e8@pks.im","subject":"Re: [PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2025-08-04T21:42:43Z","receivedAt":"2025-08-04T21:42:45Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Mon, Aug 04, 2025 at 10:17:18AM +0200, Patrick Steinhardt wrote:\n> When writing a new commit graph we have a couple of counters that\n> provide statistics around what kind of bloom filters we have or have not\n\ns/bloom/Bloom\n\n> written. These counters naturally count from zero and are only ever\n> incremented, but they use a signed integer as type regardless.\n>\n> Refactor those fields to be of type `size_t` instead.\n\nI have some thoughts about this, but I see that others do as well, so\nI'll refrain from sharing them here and instead join the discussion in\nthe sub-thread.\n\nThanks,\nTaylor\n"},{"id":"523484","messageId":"aJEppnTkY+66IEza@nand.local","threadId":"63902","inReplyTo":"xmqq5xf35429.fsf@gitster.g","subject":"Re: [PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2025-08-04T21:44:06Z","receivedAt":"2025-08-04T21:44:12Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Mon, Aug 04, 2025 at 11:34:22AM -0700, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n>\n> > On Mon, Aug 04, 2025 at 11:13:28AM +0200, Oswald Buddenhagen wrote:\n> >> On Mon, Aug 04, 2025 at 10:17:18AM +0200, Patrick Steinhardt wrote:\n> >> > When writing a new commit graph we have a couple of counters that\n> >> > provide statistics around what kind of bloom filters we have or have not\n> >> > written. These counters naturally count from zero and are only ever\n> >> > incremented, but they use a signed integer as type regardless.\n> >> >\n> >> > Refactor those fields to be of type `size_t` instead.\n> >> >\n> >> mind elaborating on that choice?\n> >\n> > We tend to use `size_t` when counting stuff.\n>\n> And I would have to say that it is wrong and we need to wean\n> ourselves from such a superstition.  Unless you are measuring how\n> big a memory block you ask from the allocator, the platform natural\n> integer is often the right type to do the counting.\n>\n> Each of your \"stuff\" may weigh N megabytes in core, and if you have\n> M of them, you may have to ask (N*2**20)*M bytes of memory from the\n> allocator.  Your (N*2**20)*M must fit size_t _and_ you must compute\n> it without overflowing or wrapping around.\n>\n> None of the above mean you have to express N in size_t, though.\n> And more importantly, nobody gives you any extra guarantee that you\n> would compute the result correctly if you used size_t.  You can write\n> the right code with platform natural integer, and you have to take\n> the same care (e.g. by using st_mult()) to catch integer overflows\n> even if you used size_t.\n\nAgreed. I think it makes sense to use size_t to keep track of, say, the\nlength and allocated size of a buffer, but when it comes to \"counting\"\nsomething that isn't directly related to memory allocation or pointer\narithmetic, size_t is usually not the right choice.\n\nFor instance, the MIDX code counts the number of objects and packs in a\ngiven MIDX (and likewise for its base MIDX(s)), but those are all\nuint32_t. You could make the case to say that, \"well, they are encoded\nin the file format as 4-byte unsigned values, so we should treat them\nthe same way in memory at read-time\", and I think that's reasonable. In\nthat instance, using \"int\" would be the wrong choice, since I have\ndefinitely seen repositories that have in excess of 2^32-1 objects.\nBut there is no reason that we shouldn't use size_t to make that count.\n\n> > ... Regarding the data size I\n> > don't really think that matters much. It's not like we have hundreds of\n> > thousands of commit graphs in-memory at any point in time.\n>\n> Aren't you saying that a platform natural integer is a much better\n> fit?\n>\n> As to signedness, it sometimes is better for a struct member that is\n> used to record the number of \"stuff\" you have to be a signed integer\n> that is initialized to -1 to signal \"we haven't counted so we do not\n> yet know how many there are\".  So\n>\n>     These counters naturally count from zero and are only ever\n>     incremented.\n>\n> is not always a valid excuse to insist that such a variable must be\n> unsigned.\n\nI wrote these counters in 312cff5207 (bloom: split 'get_bloom_filter()'\nin two, 2020-09-16) and 59f0d5073f (bloom: encode out-of-bounds filters\nas non-empty, 2020-09-17), and I don't see a compelling reason that\nthese should be unsigned.\n\nIt's true that we don't have any need for negative values here since we\nare counting from zero, but I don't think that alone justifies changing\nthe signed-ness here.\n\nIs there a reason beyond \"these are always non-negative\" that changing\nthe signed-ness is warranted? If so, let's discuss that and make sure\nthat it is documented in the commit message. If not, I think we could\ndrop this patch (and optionally the patch before it as well).\n\nThanks,\nTaylor\n"},{"id":"523485","messageId":"aJErqjDHudSeyNHr@nand.local","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-3-850d626eb2e8@pks.im","subject":"Re: [PATCH 3/9] commit-graph: fix type for some write options","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2025-08-04T21:52:42Z","receivedAt":"2025-08-04T21:59:02Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Mon, Aug 04, 2025 at 10:17:19AM +0200, Patrick Steinhardt wrote:\n> The options \"max-commits\" and \"size-multiple\" are both supposed to be\n> positive integers and are documented as such, but we use a signed\n> integer field to store them. This causes sign comparison warnings in\n> `split_graph_merge_strategy()` because we end up comparing the option\n> values with the observed number of commits.\n>\n> Fix the issue by converting the fields to be unsigned and convert the\n> options to use `OPT_UNSIGNED()` accordingly. This macro has only been\n> introduced recently, which might explain why the option values were\n> signed in the first place.\n\nI have the same general feeling about this patch as the previous one:\nthe -Wsign-compare warnings here are a bit of a red herring.\n\nThat said, I do think that we need stricter validation for these\noptions. Following the --size-multiple example, for instance, we get\nthis rather unfriendly error message if we pass a bogus value:\n\n    $ git.compile commit-graph write --split --size-multiple=-1 --reachable\n    fatal: size_t overflow: 18446744073709551615 * 34\n\nThis happens as a result of in\ncommit-graph.c::split_graph_merge_strategy() doing the following:\n\n    while (g && (g->num_commits <= st_mult(size_mult, num_commits) ||\n                 (max_commits && num_commits > max_commits))) {\n\n, where size_mult is changed from a size_t to an int implicitly when\nassigning it to the stack-local \"size_mult\" variable.\n\nIndeed, this patch does improve that warning, but I am not convinced\nthat changing the type is the right way to go about improving the error\nmessage in and of itself.\n\nThanks,\nTaylor\n"},{"id":"523486","messageId":"aJEuZnhxbJcfdWFw@nand.local","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-4-850d626eb2e8@pks.im","subject":"Re: [PATCH 4/9] commit-graph: fix sign comparison warnings","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2025-08-04T22:04:22Z","receivedAt":"2025-08-04T22:04:24Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Mon, Aug 04, 2025 at 10:17:20AM +0200, Patrick Steinhardt wrote:\n> The \"commit-graph.c\" file has a bunch of sign comparison warnings:\n>\n>   - There are a bunch of variables that are declared as signed integers\n>     even though they are used to count entities, like for example\n>     `num_commit_graphs_before` and `num_commit_graphs_after`.\n\nI have similar thoughts as in the previous patch about this spot, too.\n\n>   - There are several cases where we use signed loop variables to\n>     iterate through an unsigned entity count.\n\nHere I am more sympathetic to using a size_t to count the number of\nallocated elements in some array/buffer.\n\n>   - The bloom settings hash version is being assigned `-1` even though\n>     it's an unsigned value. This is used to indicate an unspecified\n>     value and relies on 1's complement.\n\nOK. I think that comparing \"-1\" to an unsigned value is meant equivalent\nto saying \"are all 32 of these bits set\"? But making it explicit seems\nreasonable, since it's not immediately clear from reading this function\nthat 'hash_version' is unsigned.\n\n> @@ -622,7 +621,7 @@ int open_commit_graph_chain(const char *chain_file,\n>  \t\tclose(*fd);\n>  \t\treturn 0;\n>  \t}\n> -\tif (st->st_size < the_hash_algo->hexsz) {\n> +\tif (st->st_size < (ssize_t) the_hash_algo->hexsz) {\n\nI understand why the compiler is telling you to make hexsz a signed\nquantity, but I am not sure that the cast here is aiding the reader, nor\nam I sure that it is making the code safer.\n\nThanks,\nTaylor\n"},{"id":"523487","messageId":"aJEujQnssKDNBWPW@nand.local","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-5-850d626eb2e8@pks.im","subject":"Re: [PATCH 5/9] commit-graph: stop using `the_hash_algo` via macros","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2025-08-04T22:05:01Z","receivedAt":"2025-08-04T22:05:03Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Mon, Aug 04, 2025 at 10:17:21AM +0200, Patrick Steinhardt wrote:\n> We have two macros `GRAPH_DATA_WIDTH` and `GRAPH_MIN_SIZE` that compute\n> hash-dependent sizes. They do so by using the global `the_hash_algo`\n> variable though, which we want to get rid of over time.\n>\n> Convert these macros into functions that accept the hash algorithm as\n> input parameter. Adapt callers accordingly.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  commit-graph.c | 25 ++++++++++++++++---------\n>  1 file changed, 16 insertions(+), 9 deletions(-)\n\nVery nice.\n\nThanks,\nTaylor\n"},{"id":"523488","messageId":"aJEvEB0DXcnmwme8@nand.local","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-6-850d626eb2e8@pks.im","subject":"Re: [PATCH 6/9] commit-graph: store the hash algorithm instead of its length","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2025-08-04T22:07:12Z","receivedAt":"2025-08-04T22:07:14Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Mon, Aug 04, 2025 at 10:17:22AM +0200, Patrick Steinhardt wrote:\n> The commit-graph stores the length of the hash algorithm it uses. In\n> subsequent commits we'll need to pass the whole hash algorithm around\n> though, which we currently don't have access to.\n>\n> Refactor the code so that we store the hash algorithm instead of only\n> its size.\n>\n> Signed-off-by: Patrick Steinhardt <ps@pks.im>\n> ---\n>  commit-graph.c | 36 ++++++++++++++++++------------------\n>  commit-graph.h |  2 +-\n>  2 files changed, 19 insertions(+), 19 deletions(-)\n\nAlso makes sense. I briefly wondered about hash version mismatches, but\nparse_commit_graph() already covers us here by comparing the\nhash_version field written in the commit-graph's header against\noid_version(the_hash_algo).\n\nThanks,\nTaylor\n"},{"id":"523490","messageId":"aJEvzR4wuve/9ltU@nand.local","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-7-850d626eb2e8@pks.im","subject":"Re: [PATCH 7/9] commit-graph: stop using `the_hash_algo`","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2025-08-04T22:10:21Z","receivedAt":"2025-08-04T22:10:34Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Mon, Aug 04, 2025 at 10:17:23AM +0200, Patrick Steinhardt wrote:\n> Stop using `the_hash_algo` as it implicitly relies on `the_repository`.\n> Instead, we either use the hash algo provided via the context or, if\n> there is no such hash algo, we use `the_repository` explicitly. Such\n> uses will be removed in subsequent commits.\n\nSeems reasonable, and the implementation looks straightforward to me,\nhowever I wonder...\n\n> @@ -129,6 +130,7 @@ struct repo_settings;\n>   * prior to calling parse_commit_graph().\n>   */\n>  struct commit_graph *parse_commit_graph(struct repo_settings *s,\n> +\t\t\t\t\tconst struct git_hash_algo *hash_algo,\n>  \t\t\t\t\tvoid *graph_map, size_t graph_size);\n\n...does it make more sense to take a 'struct repository *' here instead\nof passing both its settings and hash_algo separately? Is there a\nscenario where we would want to parse a commit graph with a (settings,\nhash_algo) pair that does not match that of any single repository?\n\nThanks,\nTaylor\n"},{"id":"523491","messageId":"aJEv9vcdtsn7WGc8@nand.local","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-8-850d626eb2e8@pks.im","subject":"Re: [PATCH 8/9] commit-graph: stop using `the_repository`","fromName":"Taylor Blau","fromEmail":"me@ttaylorr.com","sentAt":"2025-08-04T22:11:02Z","receivedAt":"2025-08-04T22:11:04Z","isPatch":true,"sender":{"key":"me@ttaylorr.com","avatar":"https://avatars.githubusercontent.com/u/301000140?v=4"},"body":"On Mon, Aug 04, 2025 at 10:17:24AM +0200, Patrick Steinhardt wrote:\n> ---\n>  builtin/commit.c |  2 +-\n>  builtin/merge.c  |  2 +-\n>  commit-graph.c   | 79 ++++++++++++++++++++++++++++----------------------------\n>  commit-graph.h   |  2 +-\n>  4 files changed, 43 insertions(+), 42 deletions(-)\n\nLooking good.\n\nThanks,\nTaylor\n"},{"id":"523501","messageId":"ad426013-bca4-4243-9e80-7d002f0eb808@gmail.com","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","subject":"Re: [PATCH 0/9] commit-graph: remove reliance on global state","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2025-08-05T04:27:42Z","receivedAt":"2025-08-05T04:27:44Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 8/4/25 1:17 AM, Patrick Steinhardt wrote:\n> Hi,\n> \n> this patch series is another step on our long road towards not having\n> global state. In addition to that, as commit-graphs are part of the\n> object database layer, this is also another step towards pluggable\n> object databases.\n\nThanks for carefully working through this code full of bad patterns\nand fixing not just the bare minimum to get it working. Each change\nwas sufficiently motivated and carefully done. LGTM.\n\nThanks,\n-Stolee\n"},{"id":"523562","messageId":"xmqqv7n13ipe.fsf@gitster.g","threadId":"63902","inReplyTo":"xmqq5xf35429.fsf@gitster.g","subject":"Re: [PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-08-05T15:13:17Z","receivedAt":"2025-08-05T15:13:20Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Each of your \"stuff\" may weigh N megabytes in core, and if you have\n> M of them, you may have to ask (N*2**20)*M bytes of memory from the\n> allocator.  Your (N*2**20)*M must fit size_t _and_ you must compute\n> it without overflowing or wrapping around.\n>\n> None of the above mean you have to express N in size_t, though.\n\nSmall correction.  I meant \"there is no reason to count M in size_t\"\nin the above.  I am perfectly OK with expressing N in size_t.\n"},{"id":"523635","messageId":"aJL06Nlee6CR-KK0@pks.im","threadId":"63902","inReplyTo":"aJEppnTkY+66IEza@nand.local","subject":"Re: [PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T06:23:36Z","receivedAt":"2025-08-06T06:23:43Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Mon, Aug 04, 2025 at 05:44:06PM -0400, Taylor Blau wrote:\n> On Mon, Aug 04, 2025 at 11:34:22AM -0700, Junio C Hamano wrote:\n> > Patrick Steinhardt <ps@pks.im> writes:\n> > Aren't you saying that a platform natural integer is a much better\n> > fit?\n> >\n> > As to signedness, it sometimes is better for a struct member that is\n> > used to record the number of \"stuff\" you have to be a signed integer\n> > that is initialized to -1 to signal \"we haven't counted so we do not\n> > yet know how many there are\".  So\n> >\n> >     These counters naturally count from zero and are only ever\n> >     incremented.\n> >\n> > is not always a valid excuse to insist that such a variable must be\n> > unsigned.\n> \n> I wrote these counters in 312cff5207 (bloom: split 'get_bloom_filter()'\n> in two, 2020-09-16) and 59f0d5073f (bloom: encode out-of-bounds filters\n> as non-empty, 2020-09-17), and I don't see a compelling reason that\n> these should be unsigned.\n\nI think that is going backwards though: the question to ask is why\nshould these be signed if they cannot ever be negative?\n\n> It's true that we don't have any need for negative values here since we\n> are counting from zero, but I don't think that alone justifies changing\n> the signed-ness here.\n> \n> Is there a reason beyond \"these are always non-negative\" that changing\n> the signed-ness is warranted? If so, let's discuss that and make sure\n> that it is documented in the commit message. If not, I think we could\n> drop this patch (and optionally the patch before it as well).\n\nYes, there is: it makes code easier to reason about for the reader, and\nit means that we don't have to guard ourselves against negative values.\n\nIf I see a counting variable that is signed I immediately jump to the\nquestion of whether or not it can ever be a negative value. I assume\nthat the author of this code _intentfully_ made it signed to cater to a\nspecific edge case.\n\nWhether or not we should be using `size_t`... I don't mind that one too\nmuch, and I'm fine to use `unsigned` instead. But I really think that we\nshould do our best and help readers by using the proper type for the\ntask at hand and not let them figure out whether or not they have to\ncare about edge cases where the counting value could be negative.\n\nPatrick\n"},{"id":"523636","messageId":"aJL7witwAASbQvXZ@pks.im","threadId":"63902","inReplyTo":"aJEuZnhxbJcfdWFw@nand.local","subject":"Re: [PATCH 4/9] commit-graph: fix sign comparison warnings","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T06:52:50Z","receivedAt":"2025-08-06T06:52:57Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Mon, Aug 04, 2025 at 06:04:22PM -0400, Taylor Blau wrote:\n> On Mon, Aug 04, 2025 at 10:17:20AM +0200, Patrick Steinhardt wrote:\n> > The \"commit-graph.c\" file has a bunch of sign comparison warnings:\n> >\n> >   - There are a bunch of variables that are declared as signed integers\n> >     even though they are used to count entities, like for example\n> >     `num_commit_graphs_before` and `num_commit_graphs_after`.\n> \n> I have similar thoughts as in the previous patch about this spot, too.\n\nI'll convert these to be `uint32_t` instead of `size_t`. We already use\nthat type to iterate through these counters anyway.\n\n> > @@ -622,7 +621,7 @@ int open_commit_graph_chain(const char *chain_file,\n> >  \t\tclose(*fd);\n> >  \t\treturn 0;\n> >  \t}\n> > -\tif (st->st_size < the_hash_algo->hexsz) {\n> > +\tif (st->st_size < (ssize_t) the_hash_algo->hexsz) {\n> \n> I understand why the compiler is telling you to make hexsz a signed\n> quantity, but I am not sure that the cast here is aiding the reader, nor\n> am I sure that it is making the code safer.\n\nNo, it definitely isn't. What makes the code safer is that from now on\nwe'll get warnings about signedness mismatches.\n\nPatrick\n"},{"id":"523637","messageId":"aJL7z2kHXCW1exWH@pks.im","threadId":"63902","inReplyTo":"aJEvzR4wuve/9ltU@nand.local","subject":"Re: [PATCH 7/9] commit-graph: stop using `the_hash_algo`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T06:53:03Z","receivedAt":"2025-08-06T06:53:08Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Mon, Aug 04, 2025 at 06:10:21PM -0400, Taylor Blau wrote:\n> On Mon, Aug 04, 2025 at 10:17:23AM +0200, Patrick Steinhardt wrote:\n> > Stop using `the_hash_algo` as it implicitly relies on `the_repository`.\n> > Instead, we either use the hash algo provided via the context or, if\n> > there is no such hash algo, we use `the_repository` explicitly. Such\n> > uses will be removed in subsequent commits.\n> \n> Seems reasonable, and the implementation looks straightforward to me,\n> however I wonder...\n> \n> > @@ -129,6 +130,7 @@ struct repo_settings;\n> >   * prior to calling parse_commit_graph().\n> >   */\n> >  struct commit_graph *parse_commit_graph(struct repo_settings *s,\n> > +\t\t\t\t\tconst struct git_hash_algo *hash_algo,\n> >  \t\t\t\t\tvoid *graph_map, size_t graph_size);\n> \n> ...does it make more sense to take a 'struct repository *' here instead\n> of passing both its settings and hash_algo separately? Is there a\n> scenario where we would want to parse a commit graph with a (settings,\n> hash_algo) pair that does not match that of any single repository?\n\nFair. That'd also allow us to move the call of `prepare_repo_settings()`\ninto this function.\n\nThere's one catch though: in \"oss-fuzz/fuzz-commit-graph.c\" we manually\nstub out both the repository's hash function and its settings. But we\ncan appease it by also setting `the_repository->settings.initialized`,\nwhich ensures that we won't try to populate the settings anymore.\n\nWill amend.\n\nPatrick\n"},{"id":"523638","messageId":"aJL71OK_52-nQ9XQ@pks.im","threadId":"63902","inReplyTo":"ad426013-bca4-4243-9e80-7d002f0eb808@gmail.com","subject":"Re: [PATCH 0/9] commit-graph: remove reliance on global state","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T06:53:08Z","receivedAt":"2025-08-06T06:53:14Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Mon, Aug 04, 2025 at 09:27:42PM -0700, Derrick Stolee wrote:\n> On 8/4/25 1:17 AM, Patrick Steinhardt wrote:\n> > Hi,\n> > \n> > this patch series is another step on our long road towards not having\n> > global state. In addition to that, as commit-graphs are part of the\n> > object database layer, this is also another step towards pluggable\n> > object databases.\n> \n> Thanks for carefully working through this code full of bad patterns\n> and fixing not just the bare minimum to get it working. Each change\n> was sufficiently motivated and carefully done. LGTM.\n\nThanks for your review!\n\nPatrick\n"},{"id":"523642","messageId":"20250806-b4-pks-commit-graph-wo-the-repository-v2-0-911bae638e61@pks.im","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","subject":"[PATCH v2 00/10] commit-graph: remove reliance on global state","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T12:00:05Z","receivedAt":"2025-08-06T12:00:21Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Hi,\n\nthis patch series is another step on our long road towards not having\nglobal state. In addition to that, as commit-graphs are part of the\nobject database layer, this is also another step towards pluggable\nobject databases.\n\nChanges in v2:\n  - Use `unsigned` instead of `size_t` to count number of Bloom filters.\n  - Use `uint32_t` instead of `size_t` for number of commit graphs,\n    as this type is also used to iterate through this count already.\n  - Refactor `parse_commit_graph()` to take a repository instead of both\n    repo settings and a hash algo.\n  - Link to v1: https://lore.kernel.org/r/20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im\n\nThanks!\n\nPatrick\n\n---\nPatrick Steinhardt (10):\n      trace2: introduce function to trace unsigned integers\n      commit-graph: stop using signed integers to count Bloom filters\n      commit-graph: fix type for some write options\n      commit-graph: fix sign comparison warnings\n      commit-graph: stop using `the_hash_algo` via macros\n      commit-graph: store the hash algorithm instead of its length\n      commit-graph: refactor `parse_commit_graph()` to take a repository\n      commit-graph: stop using `the_hash_algo`\n      commit-graph: stop using `the_repository`\n      commit-graph: stop passing in redundant repository\n\n builtin/commit-graph.c       |  13 +-\n builtin/commit.c             |   2 +-\n builtin/merge.c              |   2 +-\n commit-graph.c               | 371 +++++++++++++++++++++----------------------\n commit-graph.h               |  25 ++-\n oss-fuzz/fuzz-commit-graph.c |   6 +-\n t/helper/test-read-graph.c   |   2 +-\n trace2.c                     |  14 ++\n trace2.h                     |   9 ++\n 9 files changed, 227 insertions(+), 217 deletions(-)\n\nRange-diff versus v1:\n\n 1:  cb92085a3b =  1:  a25e9cdbcc trace2: introduce function to trace unsigned integers\n 2:  25520448c6 !  2:  e03ca21ec2 commit-graph: stop using signed integers to count bloom filters\n    @@ Metadata\n     Author: Patrick Steinhardt <ps@pks.im>\n     \n      ## Commit message ##\n    -    commit-graph: stop using signed integers to count bloom filters\n    +    commit-graph: stop using signed integers to count Bloom filters\n     \n         When writing a new commit graph we have a couple of counters that\n    -    provide statistics around what kind of bloom filters we have or have not\n    +    provide statistics around what kind of Bloom filters we have or have not\n         written. These counters naturally count from zero and are only ever\n         incremented, but they use a signed integer as type regardless.\n     \n    -    Refactor those fields to be of type `size_t` instead.\n    +    Refactor those fields to be unsigned instead. Using an unsigned type\n    +    makes it explicit to the reader that they never have to worry about\n    +    negative values and thus makes the code easier to understand.\n     \n         Signed-off-by: Patrick Steinhardt <ps@pks.im>\n     \n    @@ commit-graph.c: struct write_commit_graph_context {\n     -\tint count_bloom_filter_trunc_empty;\n     -\tint count_bloom_filter_trunc_large;\n     -\tint count_bloom_filter_upgraded;\n    -+\tsize_t count_bloom_filter_computed;\n    -+\tsize_t count_bloom_filter_not_computed;\n    -+\tsize_t count_bloom_filter_trunc_empty;\n    -+\tsize_t count_bloom_filter_trunc_large;\n    -+\tsize_t count_bloom_filter_upgraded;\n    ++\tunsigned count_bloom_filter_computed;\n    ++\tunsigned count_bloom_filter_not_computed;\n    ++\tunsigned count_bloom_filter_trunc_empty;\n    ++\tunsigned count_bloom_filter_trunc_large;\n    ++\tunsigned count_bloom_filter_upgraded;\n      };\n      \n      static int write_graph_chunk_fanout(struct hashfile *f,\n 3:  12e150a326 =  3:  d569434715 commit-graph: fix type for some write options\n 4:  0bdaff4e76 !  4:  3f820e3347 commit-graph: fix sign comparison warnings\n    @@ Commit message\n             quantity, we still return a signed integer that we then later\n             compare with unsigned values.\n     \n    -      - The bloom settings hash version is being assigned `-1` even though\n    +      - The Bloom settings hash version is being assigned `-1` even though\n             it's an unsigned value. This is used to indicate an unspecified\n             value and relies on 1's complement.\n     \n    @@ commit-graph.c: struct write_commit_graph_context {\n      \tchar *base_graph_name;\n     -\tint num_commit_graphs_before;\n     -\tint num_commit_graphs_after;\n    -+\tsize_t num_commit_graphs_before;\n    -+\tsize_t num_commit_graphs_after;\n    ++\tuint32_t num_commit_graphs_before;\n    ++\tuint32_t num_commit_graphs_after;\n      \tchar **commit_graph_filenames_before;\n      \tchar **commit_graph_filenames_after;\n      \tchar **commit_graph_hash_after;\n 5:  6e5d4da7f1 =  5:  c3be366e36 commit-graph: stop using `the_hash_algo` via macros\n 6:  8e8bf531d1 =  6:  2476994769 commit-graph: store the hash algorithm instead of its length\n -:  ---------- >  7:  b582b49437 commit-graph: refactor `parse_commit_graph()` to take a repository\n 7:  20bce2f981 !  8:  0d0bd20ceb commit-graph: stop using `the_hash_algo`\n    @@ commit-graph.c: struct commit_graph *load_commit_graph_one_fd_st(struct reposito\n      \t\tclose(fd);\n      \t\terror(_(\"commit-graph file is too small\"));\n      \t\treturn NULL;\n    -@@ commit-graph.c: struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n    - \tgraph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);\n    - \tclose(fd);\n    - \tprepare_repo_settings(r);\n    --\tret = parse_commit_graph(&r->settings, graph_map, graph_size);\n    -+\tret = parse_commit_graph(&r->settings, r->hash_algo, graph_map, graph_size);\n    - \n    - \tif (ret)\n    - \t\tret->odb_source = source;\n     @@ commit-graph.c: static int graph_read_commit_data(const unsigned char *chunk_start,\n      \t\t\t\t  size_t chunk_size, void *data)\n      {\n    @@ commit-graph.c: static int graph_read_commit_data(const unsigned char *chunk_sta\n      \t\treturn error(_(\"commit-graph commit data chunk is wrong size\"));\n      \tg->chunk_commit_data = chunk_start;\n      \treturn 0;\n    -@@ commit-graph.c: static int graph_read_bloom_data(const unsigned char *chunk_start,\n    - }\n    - \n    - struct commit_graph *parse_commit_graph(struct repo_settings *s,\n    -+\t\t\t\t\tconst struct git_hash_algo *hash_algo,\n    - \t\t\t\t\tvoid *graph_map, size_t graph_size)\n    - {\n    - \tconst unsigned char *data;\n    -@@ commit-graph.c: struct commit_graph *parse_commit_graph(struct repo_settings *s,\n    - \tif (!graph_map)\n    - \t\treturn NULL;\n    - \n    --\tif (graph_size < graph_min_size(the_hash_algo))\n    -+\tif (graph_size < graph_min_size(hash_algo))\n    - \t\treturn NULL;\n    - \n    - \tdata = (const unsigned char *)graph_map;\n    -@@ commit-graph.c: struct commit_graph *parse_commit_graph(struct repo_settings *s,\n    - \t}\n    - \n    - \thash_version = *(unsigned char*)(data + 5);\n    --\tif (hash_version != oid_version(the_hash_algo)) {\n    -+\tif (hash_version != oid_version(hash_algo)) {\n    - \t\terror(_(\"commit-graph hash version %X does not match version %X\"),\n    --\t\t      hash_version, oid_version(the_hash_algo));\n    -+\t\t      hash_version, oid_version(hash_algo));\n    - \t\treturn NULL;\n    - \t}\n    - \n    - \tgraph = alloc_commit_graph();\n    - \n    --\tgraph->hash_algo = the_hash_algo;\n    -+\tgraph->hash_algo = hash_algo;\n    - \tgraph->num_chunks = *(unsigned char*)(data + 6);\n    - \tgraph->data = graph_map;\n    - \tgraph->data_len = graph_size;\n    - \n    - \tif (graph_size < GRAPH_HEADER_SIZE +\n    - \t\t\t (graph->num_chunks + 1) * CHUNK_TOC_ENTRY_SIZE +\n    --\t\t\t GRAPH_FANOUT_SIZE + the_hash_algo->rawsz) {\n    -+\t\t\t GRAPH_FANOUT_SIZE + hash_algo->rawsz) {\n    - \t\terror(_(\"commit-graph file is too small to hold %u chunks\"),\n    - \t\t      graph->num_chunks);\n    - \t\tfree(graph);\n     @@ commit-graph.c: static int add_graph_to_chain(struct commit_graph *g,\n      }\n      \n    @@ commit-graph.h: struct string_list;\n      \n      /*\n       * Given a commit struct, try to fill the commit struct info, including:\n    -@@ commit-graph.h: struct repo_settings;\n    -  * prior to calling parse_commit_graph().\n    -  */\n    - struct commit_graph *parse_commit_graph(struct repo_settings *s,\n    -+\t\t\t\t\tconst struct git_hash_algo *hash_algo,\n    - \t\t\t\t\tvoid *graph_map, size_t graph_size);\n    - \n    - /*\n    -\n    - ## oss-fuzz/fuzz-commit-graph.c ##\n    -@@\n    - #include \"repository.h\"\n    - \n    - struct commit_graph *parse_commit_graph(struct repo_settings *s,\n    -+\t\t\t\t\tconst struct git_hash_algo *hash_algo,\n    - \t\t\t\t\tvoid *graph_map, size_t graph_size);\n    - \n    - int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n    -@@ oss-fuzz/fuzz-commit-graph.c: int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n    - \trepo_set_hash_algo(the_repository, GIT_HASH_SHA1);\n    - \tthe_repository->settings.commit_graph_generation_version = 2;\n    - \tthe_repository->settings.commit_graph_changed_paths_version = 1;\n    --\tg = parse_commit_graph(&the_repository->settings, (void *)data, size);\n    -+\tg = parse_commit_graph(&the_repository->settings, the_repository->hash_algo,\n    -+\t\t\t       (void *)data, size);\n    - \trepo_clear(the_repository);\n    - \tfree_commit_graph(g);\n    - \n 8:  424567998e !  9:  a86c1ab958 commit-graph: stop using `the_repository`\n    @@ commit-graph.c: void git_test_write_commit_graph_or_die(void)\n      \t\tdie(\"failed to write commit-graph under GIT_TEST_COMMIT_GRAPH\");\n      }\n      \n    -@@ commit-graph.c: struct commit_graph *parse_commit_graph(struct repo_settings *s,\n    - \t}\n    - \n    - \toidread(&graph->oid, graph->data + graph->data_len - graph->hash_algo->rawsz,\n    --\t\tthe_repository->hash_algo);\n    -+\t\thash_algo);\n    - \n    - \tfree_chunkfile(cf);\n    - \treturn graph;\n     @@ commit-graph.c: static int add_graph_to_chain(struct commit_graph *g,\n      \t\tif (!cur_g ||\n      \t\t    !oideq(&oids[n], &cur_g->oid) ||\n 9:  cff4bc0329 ! 10:  70a7f6fecf commit-graph: stop passing in redundant repository\n    @@ commit-graph.c: struct commit_graph *load_commit_graph_one_fd_st(struct reposito\n      \t\tclose(fd);\n      \t\terror(_(\"commit-graph file is too small\"));\n      \t\treturn NULL;\n    - \t}\n    +@@ commit-graph.c: struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n      \tgraph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);\n      \tclose(fd);\n    --\tprepare_repo_settings(r);\n    --\tret = parse_commit_graph(&r->settings, r->hash_algo, graph_map, graph_size);\n    -+\tprepare_repo_settings(source->odb->repo);\n    -+\tret = parse_commit_graph(&source->odb->repo->settings, source->odb->repo->hash_algo,\n    -+\t\t\t\t graph_map, graph_size);\n      \n    +-\tret = parse_commit_graph(r, graph_map, graph_size);\n    ++\tret = parse_commit_graph(source->odb->repo, graph_map, graph_size);\n      \tif (ret)\n      \t\tret->odb_source = source;\n    -@@ commit-graph.c: struct commit_graph *parse_commit_graph(struct repo_settings *s,\n    + \telse\n    +@@ commit-graph.c: struct commit_graph *parse_commit_graph(struct repository *r,\n      \treturn NULL;\n      }\n      \n\n---\nbase-commit: e813a0200a7121b97fec535f0d0b460b0a33356c\nchange-id: 20250717-b4-pks-commit-graph-wo-the-repository-1dc2cacbc8e3\n\n"},{"id":"523643","messageId":"20250806-b4-pks-commit-graph-wo-the-repository-v2-1-911bae638e61@pks.im","threadId":"63902","inReplyTo":"20250806-b4-pks-commit-graph-wo-the-repository-v2-0-911bae638e61@pks.im","subject":"[PATCH v2 01/10] trace2: introduce function to trace unsigned integers","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T12:00:06Z","receivedAt":"2025-08-06T12:00:23Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"While we have `trace2_data_intmax()`, there is no equivalent function\nthat takes an unsigned integer. Introduce `trace2_data_uintmax()` to\nplug this gap.\n\nThis function will be used in a subsequent commit.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n trace2.c | 14 ++++++++++++++\n trace2.h |  9 +++++++++\n 2 files changed, 23 insertions(+)\n\ndiff --git a/trace2.c b/trace2.c\nindex c23c0a227b..a687944f7b 100644\n--- a/trace2.c\n+++ b/trace2.c\n@@ -948,6 +948,20 @@ void trace2_data_intmax_fl(const char *file, int line, const char *category,\n \tstrbuf_release(&buf_string);\n }\n \n+void trace2_data_uintmax_fl(const char *file, int line, const char *category,\n+\t\t\t    const struct repository *repo, const char *key,\n+\t\t\t    uintmax_t value)\n+{\n+\tstruct strbuf buf_string = STRBUF_INIT;\n+\n+\tif (!trace2_enabled)\n+\t\treturn;\n+\n+\tstrbuf_addf(&buf_string, \"%\" PRIuMAX, value);\n+\ttrace2_data_string_fl(file, line, category, repo, key, buf_string.buf);\n+\tstrbuf_release(&buf_string);\n+}\n+\n void trace2_data_json_fl(const char *file, int line, const char *category,\n \t\t\t const struct repository *repo, const char *key,\n \t\t\t const struct json_writer *value)\ndiff --git a/trace2.h b/trace2.h\nindex e4f23784e4..115c45a1eb 100644\n--- a/trace2.h\n+++ b/trace2.h\n@@ -463,6 +463,15 @@ void trace2_data_intmax_fl(const char *file, int line, const char *category,\n \ttrace2_data_intmax_fl(__FILE__, __LINE__, (category), (repo), (key), \\\n \t\t\t      (value))\n \n+void trace2_data_uintmax_fl(const char *file, int line, const char *category,\n+\t\t\t    const struct repository *repo, const char *key,\n+\t\t\t    uintmax_t value);\n+\n+#define trace2_data_uintmax(category, repo, key, value)                       \\\n+\ttrace2_data_uintmax_fl(__FILE__, __LINE__, (category), (repo), (key), \\\n+\t\t\t      (value))\n+\n+\n void trace2_data_json_fl(const char *file, int line, const char *category,\n \t\t\t const struct repository *repo, const char *key,\n \t\t\t const struct json_writer *jw);\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523644","messageId":"20250806-b4-pks-commit-graph-wo-the-repository-v2-2-911bae638e61@pks.im","threadId":"63902","inReplyTo":"20250806-b4-pks-commit-graph-wo-the-repository-v2-0-911bae638e61@pks.im","subject":"[PATCH v2 02/10] commit-graph: stop using signed integers to count Bloom filters","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T12:00:07Z","receivedAt":"2025-08-06T12:00:26Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"When writing a new commit graph we have a couple of counters that\nprovide statistics around what kind of Bloom filters we have or have not\nwritten. These counters naturally count from zero and are only ever\nincremented, but they use a signed integer as type regardless.\n\nRefactor those fields to be unsigned instead. Using an unsigned type\nmakes it explicit to the reader that they never have to worry about\nnegative values and thus makes the code easier to understand.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 30 +++++++++++++++---------------\n 1 file changed, 15 insertions(+), 15 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex bd7b6f5338..3fc1273ba5 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -1170,11 +1170,11 @@ struct write_commit_graph_context {\n \tsize_t total_bloom_filter_data_size;\n \tconst struct bloom_filter_settings *bloom_settings;\n \n-\tint count_bloom_filter_computed;\n-\tint count_bloom_filter_not_computed;\n-\tint count_bloom_filter_trunc_empty;\n-\tint count_bloom_filter_trunc_large;\n-\tint count_bloom_filter_upgraded;\n+\tunsigned count_bloom_filter_computed;\n+\tunsigned count_bloom_filter_not_computed;\n+\tunsigned count_bloom_filter_trunc_empty;\n+\tunsigned count_bloom_filter_trunc_large;\n+\tunsigned count_bloom_filter_upgraded;\n };\n \n static int write_graph_chunk_fanout(struct hashfile *f,\n@@ -1779,16 +1779,16 @@ void ensure_generations_valid(struct repository *r,\n \n static void trace2_bloom_filter_write_statistics(struct write_commit_graph_context *ctx)\n {\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-computed\",\n-\t\t\t   ctx->count_bloom_filter_computed);\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-not-computed\",\n-\t\t\t   ctx->count_bloom_filter_not_computed);\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-trunc-empty\",\n-\t\t\t   ctx->count_bloom_filter_trunc_empty);\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-trunc-large\",\n-\t\t\t   ctx->count_bloom_filter_trunc_large);\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-upgraded\",\n-\t\t\t   ctx->count_bloom_filter_upgraded);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-computed\",\n+\t\t\t    ctx->count_bloom_filter_computed);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-not-computed\",\n+\t\t\t    ctx->count_bloom_filter_not_computed);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-trunc-empty\",\n+\t\t\t    ctx->count_bloom_filter_trunc_empty);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-trunc-large\",\n+\t\t\t    ctx->count_bloom_filter_trunc_large);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-upgraded\",\n+\t\t\t    ctx->count_bloom_filter_upgraded);\n }\n \n static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523645","messageId":"20250806-b4-pks-commit-graph-wo-the-repository-v2-3-911bae638e61@pks.im","threadId":"63902","inReplyTo":"20250806-b4-pks-commit-graph-wo-the-repository-v2-0-911bae638e61@pks.im","subject":"[PATCH v2 03/10] commit-graph: fix type for some write options","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T12:00:08Z","receivedAt":"2025-08-06T12:00:29Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The options \"max-commits\" and \"size-multiple\" are both supposed to be\npositive integers and are documented as such, but we use a signed\ninteger field to store them. This causes sign comparison warnings in\n`split_graph_merge_strategy()` because we end up comparing the option\nvalues with the observed number of commits.\n\nFix the issue by converting the fields to be unsigned and convert the\noptions to use `OPT_UNSIGNED()` accordingly. This macro has only been\nintroduced recently, which might explain why the option values were\nsigned in the first place.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit-graph.c | 4 ++--\n commit-graph.c         | 5 ++---\n commit-graph.h         | 4 ++--\n 3 files changed, 6 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/commit-graph.c b/builtin/commit-graph.c\nindex 25018a0b9d..145802afb7 100644\n--- a/builtin/commit-graph.c\n+++ b/builtin/commit-graph.c\n@@ -241,9 +241,9 @@ static int graph_write(int argc, const char **argv, const char *prefix,\n \t\t\tN_(\"allow writing an incremental commit-graph file\"),\n \t\t\tPARSE_OPT_OPTARG | PARSE_OPT_NONEG,\n \t\t\twrite_option_parse_split),\n-\t\tOPT_INTEGER(0, \"max-commits\", &write_opts.max_commits,\n+\t\tOPT_UNSIGNED(0, \"max-commits\", &write_opts.max_commits,\n \t\t\tN_(\"maximum number of commits in a non-base split commit-graph\")),\n-\t\tOPT_INTEGER(0, \"size-multiple\", &write_opts.size_multiple,\n+\t\tOPT_UNSIGNED(0, \"size-multiple\", &write_opts.size_multiple,\n \t\t\tN_(\"maximum ratio between two levels of a split commit-graph\")),\n \t\tOPT_EXPIRY_DATE(0, \"expire-time\", &write_opts.expire_time,\n \t\t\tN_(\"only expire files older than a given date-time\")),\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 3fc1273ba5..ba04fe75db 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -2235,9 +2235,8 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)\n \tuint32_t num_commits;\n \tenum commit_graph_split_flags flags = COMMIT_GRAPH_SPLIT_UNSPECIFIED;\n \tuint32_t i;\n-\n-\tint max_commits = 0;\n-\tint size_mult = 2;\n+\tsize_t max_commits = 0;\n+\tsize_t size_mult = 2;\n \n \tif (ctx->opts) {\n \t\tmax_commits = ctx->opts->max_commits;\ndiff --git a/commit-graph.h b/commit-graph.h\nindex 78ab7b875b..b71cb55697 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -160,8 +160,8 @@ enum commit_graph_split_flags {\n };\n \n struct commit_graph_opts {\n-\tint size_multiple;\n-\tint max_commits;\n+\tsize_t size_multiple;\n+\tsize_t max_commits;\n \ttimestamp_t expire_time;\n \tenum commit_graph_split_flags split_flags;\n \tint max_new_filters;\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523646","messageId":"20250806-b4-pks-commit-graph-wo-the-repository-v2-4-911bae638e61@pks.im","threadId":"63902","inReplyTo":"20250806-b4-pks-commit-graph-wo-the-repository-v2-0-911bae638e61@pks.im","subject":"[PATCH v2 04/10] commit-graph: fix sign comparison warnings","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T12:00:09Z","receivedAt":"2025-08-06T12:00:33Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The \"commit-graph.c\" file has a bunch of sign comparison warnings:\n\n  - There are a bunch of variables that are declared as signed integers\n    even though they are used to count entities, like for example\n    `num_commit_graphs_before` and `num_commit_graphs_after`.\n\n  - There are several cases where we use signed loop variables to\n    iterate through an unsigned entity count.\n\n  - In `write_graph_chunk_base_1()` we count how many chunks we have\n    written in total. But while the value represents a positive\n    quantity, we still return a signed integer that we then later\n    compare with unsigned values.\n\n  - The Bloom settings hash version is being assigned `-1` even though\n    it's an unsigned value. This is used to indicate an unspecified\n    value and relies on 1's complement.\n\nFix all of these cases by either using the proper variable type or by\nadding casts as required.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 54 +++++++++++++++++++++++++++---------------------------\n 1 file changed, 27 insertions(+), 27 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex ba04fe75db..6d5b5444e7 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -1,5 +1,4 @@\n #define USE_THE_REPOSITORY_VARIABLE\n-#define DISABLE_SIGN_COMPARE_WARNINGS\n \n #include \"git-compat-util.h\"\n #include \"config.h\"\n@@ -569,7 +568,7 @@ static void validate_mixed_bloom_settings(struct commit_graph *g)\n static int add_graph_to_chain(struct commit_graph *g,\n \t\t\t      struct commit_graph *chain,\n \t\t\t      struct object_id *oids,\n-\t\t\t      int n)\n+\t\t\t      size_t n)\n {\n \tstruct commit_graph *cur_g = chain;\n \n@@ -622,7 +621,7 @@ int open_commit_graph_chain(const char *chain_file,\n \t\tclose(*fd);\n \t\treturn 0;\n \t}\n-\tif (st->st_size < the_hash_algo->hexsz) {\n+\tif (st->st_size < (ssize_t) the_hash_algo->hexsz) {\n \t\tclose(*fd);\n \t\tif (!st->st_size) {\n \t\t\t/* treat empty files the same as missing */\n@@ -643,15 +642,16 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \tstruct commit_graph *graph_chain = NULL;\n \tstruct strbuf line = STRBUF_INIT;\n \tstruct object_id *oids;\n-\tint i = 0, valid = 1, count;\n+\tint valid = 1;\n \tFILE *fp = xfdopen(fd, \"r\");\n+\tsize_t count;\n \n \tcount = st->st_size / (the_hash_algo->hexsz + 1);\n \tCALLOC_ARRAY(oids, count);\n \n \todb_prepare_alternates(r->objects);\n \n-\tfor (i = 0; i < count; i++) {\n+\tfor (size_t i = 0; i < count; i++) {\n \t\tstruct odb_source *source;\n \n \t\tif (strbuf_getline_lf(&line, fp) == EOF)\n@@ -1145,12 +1145,12 @@ struct write_commit_graph_context {\n \tint num_generation_data_overflows;\n \tunsigned long approx_nr_objects;\n \tstruct progress *progress;\n-\tint progress_done;\n+\tuint64_t progress_done;\n \tuint64_t progress_cnt;\n \n \tchar *base_graph_name;\n-\tint num_commit_graphs_before;\n-\tint num_commit_graphs_after;\n+\tuint32_t num_commit_graphs_before;\n+\tuint32_t num_commit_graphs_after;\n \tchar **commit_graph_filenames_before;\n \tchar **commit_graph_filenames_after;\n \tchar **commit_graph_hash_after;\n@@ -1181,7 +1181,7 @@ static int write_graph_chunk_fanout(struct hashfile *f,\n \t\t\t\t    void *data)\n {\n \tstruct write_commit_graph_context *ctx = data;\n-\tint i, count = 0;\n+\tsize_t i, count = 0;\n \tstruct commit **list = ctx->commits.list;\n \n \t/*\n@@ -1209,7 +1209,8 @@ static int write_graph_chunk_oids(struct hashfile *f,\n {\n \tstruct write_commit_graph_context *ctx = data;\n \tstruct commit **list = ctx->commits.list;\n-\tint count;\n+\tsize_t count;\n+\n \tfor (count = 0; count < ctx->commits.nr; count++, list++) {\n \t\tdisplay_progress(ctx->progress, ++ctx->progress_cnt);\n \t\thashwrite(f, (*list)->object.oid.hash, the_hash_algo->rawsz);\n@@ -1331,9 +1332,9 @@ static int write_graph_chunk_generation_data(struct hashfile *f,\n \t\t\t\t\t     void *data)\n {\n \tstruct write_commit_graph_context *ctx = data;\n-\tint i, num_generation_data_overflows = 0;\n+\tint num_generation_data_overflows = 0;\n \n-\tfor (i = 0; i < ctx->commits.nr; i++) {\n+\tfor (size_t i = 0; i < ctx->commits.nr; i++) {\n \t\tstruct commit *c = ctx->commits.list[i];\n \t\ttimestamp_t offset;\n \t\trepo_parse_commit(ctx->r, c);\n@@ -1355,8 +1356,8 @@ static int write_graph_chunk_generation_data_overflow(struct hashfile *f,\n \t\t\t\t\t\t      void *data)\n {\n \tstruct write_commit_graph_context *ctx = data;\n-\tint i;\n-\tfor (i = 0; i < ctx->commits.nr; i++) {\n+\n+\tfor (size_t i = 0; i < ctx->commits.nr; i++) {\n \t\tstruct commit *c = ctx->commits.list[i];\n \t\ttimestamp_t offset = commit_graph_data_at(c)->generation - c->date;\n \t\tdisplay_progress(ctx->progress, ++ctx->progress_cnt);\n@@ -1526,7 +1527,7 @@ static void add_missing_parents(struct write_commit_graph_context *ctx, struct c\n \n static void close_reachable(struct write_commit_graph_context *ctx)\n {\n-\tint i;\n+\tsize_t i;\n \tstruct commit *commit;\n \tenum commit_graph_split_flags flags = ctx->opts ?\n \t\tctx->opts->split_flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;\n@@ -1620,10 +1621,9 @@ static void compute_reachable_generation_numbers(\n \t\t\tstruct compute_generation_info *info,\n \t\t\tint generation_version)\n {\n-\tint i;\n \tstruct commit_list *list = NULL;\n \n-\tfor (i = 0; i < info->commits->nr; i++) {\n+\tfor (size_t i = 0; i < info->commits->nr; i++) {\n \t\tstruct commit *c = info->commits->list[i];\n \t\ttimestamp_t gen;\n \t\trepo_parse_commit(info->r, c);\n@@ -1714,7 +1714,7 @@ static void set_generation_v2(struct commit *c, timestamp_t t,\n \n static void compute_generation_numbers(struct write_commit_graph_context *ctx)\n {\n-\tint i;\n+\tsize_t i;\n \tstruct compute_generation_info info = {\n \t\t.r = ctx->r,\n \t\t.commits = &ctx->commits,\n@@ -1793,10 +1793,10 @@ static void trace2_bloom_filter_write_statistics(struct write_commit_graph_conte\n \n static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n {\n-\tint i;\n+\tsize_t i;\n \tstruct progress *progress = NULL;\n \tstruct commit **sorted_commits;\n-\tint max_new_filters;\n+\tsize_t max_new_filters;\n \n \tinit_bloom_filters();\n \n@@ -1814,7 +1814,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n \t\tQSORT(sorted_commits, ctx->commits.nr, commit_gen_cmp);\n \n \tmax_new_filters = ctx->opts && ctx->opts->max_new_filters >= 0 ?\n-\t\tctx->opts->max_new_filters : ctx->commits.nr;\n+\t\t(size_t) ctx->opts->max_new_filters : ctx->commits.nr;\n \n \tfor (i = 0; i < ctx->commits.nr; i++) {\n \t\tenum bloom_filter_computed computed = 0;\n@@ -2017,10 +2017,10 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx)\n \tstop_progress(&ctx->progress);\n }\n \n-static int write_graph_chunk_base_1(struct hashfile *f,\n-\t\t\t\t    struct commit_graph *g)\n+static size_t write_graph_chunk_base_1(struct hashfile *f,\n+\t\t\t\t       struct commit_graph *g)\n {\n-\tint num = 0;\n+\tsize_t num = 0;\n \n \tif (!g)\n \t\treturn 0;\n@@ -2034,7 +2034,7 @@ static int write_graph_chunk_base(struct hashfile *f,\n \t\t\t\t    void *data)\n {\n \tstruct write_commit_graph_context *ctx = data;\n-\tint num = write_graph_chunk_base_1(f, ctx->new_base_graph);\n+\tsize_t num = write_graph_chunk_base_1(f, ctx->new_base_graph);\n \n \tif (num != ctx->num_commit_graphs_after - 1) {\n \t\terror(_(\"failed to write correct number of base graph ids\"));\n@@ -2480,7 +2480,7 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)\n \t\tif (stat(path.buf, &st) < 0)\n \t\t\tcontinue;\n \n-\t\tif (st.st_mtime > expire_time)\n+\t\tif ((unsigned) st.st_mtime > expire_time)\n \t\t\tcontinue;\n \t\tif (path.len < 6 || strcmp(path.buf + path.len - 6, \".graph\"))\n \t\t\tcontinue;\n@@ -2576,7 +2576,7 @@ int write_commit_graph(struct odb_source *source,\n \t\t\tctx.changed_paths = 1;\n \n \t\t\t/* don't propagate the hash_version unless unspecified */\n-\t\t\tif (bloom_settings.hash_version == -1)\n+\t\t\tif (bloom_settings.hash_version == (unsigned) -1)\n \t\t\t\tbloom_settings.hash_version = g->bloom_filter_settings->hash_version;\n \t\t\tbloom_settings.bits_per_entry = g->bloom_filter_settings->bits_per_entry;\n \t\t\tbloom_settings.num_hashes = g->bloom_filter_settings->num_hashes;\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523647","messageId":"20250806-b4-pks-commit-graph-wo-the-repository-v2-5-911bae638e61@pks.im","threadId":"63902","inReplyTo":"20250806-b4-pks-commit-graph-wo-the-repository-v2-0-911bae638e61@pks.im","subject":"[PATCH v2 05/10] commit-graph: stop using `the_hash_algo` via macros","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T12:00:10Z","receivedAt":"2025-08-06T12:00:36Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have two macros `GRAPH_DATA_WIDTH` and `GRAPH_MIN_SIZE` that compute\nhash-dependent sizes. They do so by using the global `the_hash_algo`\nvariable though, which we want to get rid of over time.\n\nConvert these macros into functions that accept the hash algorithm as\ninput parameter. Adapt callers accordingly.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 25 ++++++++++++++++---------\n 1 file changed, 16 insertions(+), 9 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 6d5b5444e7..c4a0b12b6c 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -52,8 +52,6 @@ void git_test_write_commit_graph_or_die(void)\n #define GRAPH_CHUNKID_BLOOMDATA 0x42444154 /* \"BDAT\" */\n #define GRAPH_CHUNKID_BASE 0x42415345 /* \"BASE\" */\n \n-#define GRAPH_DATA_WIDTH (the_hash_algo->rawsz + 16)\n-\n #define GRAPH_VERSION_1 0x1\n #define GRAPH_VERSION GRAPH_VERSION_1\n \n@@ -65,8 +63,6 @@ void git_test_write_commit_graph_or_die(void)\n \n #define GRAPH_HEADER_SIZE 8\n #define GRAPH_FANOUT_SIZE (4 * 256)\n-#define GRAPH_MIN_SIZE (GRAPH_HEADER_SIZE + 4 * CHUNK_TOC_ENTRY_SIZE \\\n-\t\t\t+ GRAPH_FANOUT_SIZE + the_hash_algo->rawsz)\n \n #define CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW (1ULL << 31)\n \n@@ -79,6 +75,16 @@ define_commit_slab(topo_level_slab, uint32_t);\n define_commit_slab(commit_pos, int);\n static struct commit_pos commit_pos = COMMIT_SLAB_INIT(1, commit_pos);\n \n+static size_t graph_data_width(const struct git_hash_algo *algop)\n+{\n+\treturn algop->rawsz + 16;\n+}\n+\n+static size_t graph_min_size(const struct git_hash_algo *algop)\n+{\n+\treturn GRAPH_HEADER_SIZE + 4 * CHUNK_TOC_ENTRY_SIZE + GRAPH_FANOUT_SIZE + algop->rawsz;\n+}\n+\n static void set_commit_pos(struct repository *r, const struct object_id *oid)\n {\n \tstatic int32_t max_pos;\n@@ -257,7 +263,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \n \tgraph_size = xsize_t(st->st_size);\n \n-\tif (graph_size < GRAPH_MIN_SIZE) {\n+\tif (graph_size < graph_min_size(the_hash_algo)) {\n \t\tclose(fd);\n \t\terror(_(\"commit-graph file is too small\"));\n \t\treturn NULL;\n@@ -313,7 +319,7 @@ static int graph_read_commit_data(const unsigned char *chunk_start,\n \t\t\t\t  size_t chunk_size, void *data)\n {\n \tstruct commit_graph *g = data;\n-\tif (chunk_size / GRAPH_DATA_WIDTH != g->num_commits)\n+\tif (chunk_size / graph_data_width(the_hash_algo) != g->num_commits)\n \t\treturn error(_(\"commit-graph commit data chunk is wrong size\"));\n \tg->chunk_commit_data = chunk_start;\n \treturn 0;\n@@ -378,7 +384,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \tif (!graph_map)\n \t\treturn NULL;\n \n-\tif (graph_size < GRAPH_MIN_SIZE)\n+\tif (graph_size < graph_min_size(the_hash_algo))\n \t\treturn NULL;\n \n \tdata = (const unsigned char *)graph_map;\n@@ -900,7 +906,7 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \t\tdie(_(\"invalid commit position. commit-graph is likely corrupt\"));\n \n \tlex_index = pos - g->num_commits_in_base;\n-\tcommit_data = g->chunk_commit_data + st_mult(GRAPH_DATA_WIDTH, lex_index);\n+\tcommit_data = g->chunk_commit_data + st_mult(graph_data_width(the_hash_algo), lex_index);\n \n \tgraph_data = commit_graph_data_at(item);\n \tgraph_data->graph_pos = pos;\n@@ -1104,7 +1110,8 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\tg = g->base_graph;\n \n \tcommit_data = g->chunk_commit_data +\n-\t\t\tst_mult(GRAPH_DATA_WIDTH, graph_pos - g->num_commits_in_base);\n+\t\t\tst_mult(graph_data_width(the_hash_algo),\n+\t\t\t\tgraph_pos - g->num_commits_in_base);\n \n \toidread(&oid, commit_data, the_repository->hash_algo);\n \tset_commit_tree(c, lookup_tree(r, &oid));\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523648","messageId":"20250806-b4-pks-commit-graph-wo-the-repository-v2-6-911bae638e61@pks.im","threadId":"63902","inReplyTo":"20250806-b4-pks-commit-graph-wo-the-repository-v2-0-911bae638e61@pks.im","subject":"[PATCH v2 06/10] commit-graph: store the hash algorithm instead of its length","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T12:00:11Z","receivedAt":"2025-08-06T12:00:39Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The commit-graph stores the length of the hash algorithm it uses. In\nsubsequent commits we'll need to pass the whole hash algorithm around\nthough, which we currently don't have access to.\n\nRefactor the code so that we store the hash algorithm instead of only\nits size.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 36 ++++++++++++++++++------------------\n commit-graph.h |  2 +-\n 2 files changed, 19 insertions(+), 19 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex c4a0b12b6c..590a6972d2 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -310,7 +310,7 @@ static int graph_read_oid_lookup(const unsigned char *chunk_start,\n {\n \tstruct commit_graph *g = data;\n \tg->chunk_oid_lookup = chunk_start;\n-\tif (chunk_size / g->hash_len != g->num_commits)\n+\tif (chunk_size / g->hash_algo->rawsz != g->num_commits)\n \t\treturn error(_(\"commit-graph OID lookup chunk is the wrong size\"));\n \treturn 0;\n }\n@@ -412,7 +412,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \n \tgraph = alloc_commit_graph();\n \n-\tgraph->hash_len = the_hash_algo->rawsz;\n+\tgraph->hash_algo = the_hash_algo;\n \tgraph->num_chunks = *(unsigned char*)(data + 6);\n \tgraph->data = graph_map;\n \tgraph->data_len = graph_size;\n@@ -477,7 +477,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t\tFREE_AND_NULL(graph->bloom_filter_settings);\n \t}\n \n-\toidread(&graph->oid, graph->data + graph->data_len - graph->hash_len,\n+\toidread(&graph->oid, graph->data + graph->data_len - graph->hash_algo->rawsz,\n \t\tthe_repository->hash_algo);\n \n \tfree_chunkfile(cf);\n@@ -583,7 +583,7 @@ static int add_graph_to_chain(struct commit_graph *g,\n \t\treturn 0;\n \t}\n \n-\tif (g->chunk_base_graphs_size / g->hash_len < n) {\n+\tif (g->chunk_base_graphs_size / g->hash_algo->rawsz < n) {\n \t\twarning(_(\"commit-graph base graphs chunk is too small\"));\n \t\treturn 0;\n \t}\n@@ -593,7 +593,7 @@ static int add_graph_to_chain(struct commit_graph *g,\n \n \t\tif (!cur_g ||\n \t\t    !oideq(&oids[n], &cur_g->oid) ||\n-\t\t    !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_len, n),\n+\t\t    !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_algo->rawsz, n),\n \t\t\t    the_repository->hash_algo)) {\n \t\t\twarning(_(\"commit-graph chain does not match\"));\n \t\t\treturn 0;\n@@ -805,7 +805,7 @@ int generation_numbers_enabled(struct repository *r)\n \t\treturn 0;\n \n \tfirst_generation = get_be32(g->chunk_commit_data +\n-\t\t\t\t    g->hash_len + 8) >> 2;\n+\t\t\t\t    g->hash_algo->rawsz + 8) >> 2;\n \n \treturn !!first_generation;\n }\n@@ -849,7 +849,7 @@ void close_commit_graph(struct object_database *o)\n static int bsearch_graph(struct commit_graph *g, const struct object_id *oid, uint32_t *pos)\n {\n \treturn bsearch_hash(oid->hash, g->chunk_oid_fanout,\n-\t\t\t    g->chunk_oid_lookup, g->hash_len, pos);\n+\t\t\t    g->chunk_oid_lookup, g->hash_algo->rawsz, pos);\n }\n \n static void load_oid_from_graph(struct commit_graph *g,\n@@ -869,7 +869,7 @@ static void load_oid_from_graph(struct commit_graph *g,\n \n \tlex_index = pos - g->num_commits_in_base;\n \n-\toidread(oid, g->chunk_oid_lookup + st_mult(g->hash_len, lex_index),\n+\toidread(oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, lex_index),\n \t\tthe_repository->hash_algo);\n }\n \n@@ -911,8 +911,8 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \tgraph_data = commit_graph_data_at(item);\n \tgraph_data->graph_pos = pos;\n \n-\tdate_high = get_be32(commit_data + g->hash_len + 8) & 0x3;\n-\tdate_low = get_be32(commit_data + g->hash_len + 12);\n+\tdate_high = get_be32(commit_data + g->hash_algo->rawsz + 8) & 0x3;\n+\tdate_low = get_be32(commit_data + g->hash_algo->rawsz + 12);\n \titem->date = (timestamp_t)((date_high << 32) | date_low);\n \n \tif (g->read_generation_data) {\n@@ -930,10 +930,10 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \t\t} else\n \t\t\tgraph_data->generation = item->date + offset;\n \t} else\n-\t\tgraph_data->generation = get_be32(commit_data + g->hash_len + 8) >> 2;\n+\t\tgraph_data->generation = get_be32(commit_data + g->hash_algo->rawsz + 8) >> 2;\n \n \tif (g->topo_levels)\n-\t\t*topo_level_slab_at(g->topo_levels, item) = get_be32(commit_data + g->hash_len + 8) >> 2;\n+\t\t*topo_level_slab_at(g->topo_levels, item) = get_be32(commit_data + g->hash_algo->rawsz + 8) >> 2;\n }\n \n static inline void set_commit_tree(struct commit *c, struct tree *t)\n@@ -957,7 +957,7 @@ static int fill_commit_in_graph(struct repository *r,\n \tfill_commit_graph_info(item, g, pos);\n \n \tlex_index = pos - g->num_commits_in_base;\n-\tcommit_data = g->chunk_commit_data + st_mult(g->hash_len + 16, lex_index);\n+\tcommit_data = g->chunk_commit_data + st_mult(g->hash_algo->rawsz + 16, lex_index);\n \n \titem->object.parsed = 1;\n \n@@ -965,12 +965,12 @@ static int fill_commit_in_graph(struct repository *r,\n \n \tpptr = &item->parents;\n \n-\tedge_value = get_be32(commit_data + g->hash_len);\n+\tedge_value = get_be32(commit_data + g->hash_algo->rawsz);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n \tpptr = insert_parent_or_die(r, g, edge_value, pptr);\n \n-\tedge_value = get_be32(commit_data + g->hash_len + 4);\n+\tedge_value = get_be32(commit_data + g->hash_algo->rawsz + 4);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n \tif (!(edge_value & GRAPH_EXTRA_EDGES_NEEDED)) {\n@@ -2622,7 +2622,7 @@ int write_commit_graph(struct odb_source *source,\n \t\tstruct commit_graph *g = ctx.r->objects->commit_graph;\n \t\tfor (i = 0; i < g->num_commits; i++) {\n \t\t\tstruct object_id oid;\n-\t\t\toidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),\n+\t\t\toidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n \t\t\t\tthe_repository->hash_algo);\n \t\t\toid_array_append(&ctx.oids, &oid);\n \t\t}\n@@ -2753,7 +2753,7 @@ static int verify_one_commit_graph(struct repository *r,\n \tfor (i = 0; i < g->num_commits; i++) {\n \t\tstruct commit *graph_commit;\n \n-\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),\n+\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n \t\t\tthe_repository->hash_algo);\n \n \t\tif (i && oidcmp(&prev_oid, &cur_oid) >= 0)\n@@ -2798,7 +2798,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\ttimestamp_t generation;\n \n \t\tdisplay_progress(progress, ++(*seen));\n-\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),\n+\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n \t\t\tthe_repository->hash_algo);\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\ndiff --git a/commit-graph.h b/commit-graph.h\nindex b71cb55697..f20d28ff3a 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -84,7 +84,7 @@ struct commit_graph {\n \tconst unsigned char *data;\n \tsize_t data_len;\n \n-\tunsigned char hash_len;\n+\tconst struct git_hash_algo *hash_algo;\n \tunsigned char num_chunks;\n \tuint32_t num_commits;\n \tstruct object_id oid;\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523649","messageId":"20250806-b4-pks-commit-graph-wo-the-repository-v2-7-911bae638e61@pks.im","threadId":"63902","inReplyTo":"20250806-b4-pks-commit-graph-wo-the-repository-v2-0-911bae638e61@pks.im","subject":"[PATCH v2 07/10] commit-graph: refactor `parse_commit_graph()` to take a repository","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T12:00:12Z","receivedAt":"2025-08-06T12:00:42Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Refactor `parse_commit_graph()` so that it takes a repository instead of\ntaking repository settings. On the one hand this allows us to get rid of\ninstances where we access `the_hash_algo` by using the repository's hash\nalgorithm instead. On the other hand it also allows us to move the call\nof `prepare_repo_settings()` into the function itself.\n\nNote that there's one small catch, as the commit-graph fuzzer calls this\nfunction directly without having a fully functional repository at hand.\nAnd while the fuzzer already initializes `the_repository` with relevant\ninfo, the call to `prepare_repo_settings()` would fail because we don't\nhave a fully-initialized repository.\n\nWork around the issue by also settings `settings.initialized` to pretend\nthat we've already read the settings.\n\nWhile at it, remove the redundant `parse_commit_graph()` declaration in\nthe fuzzer. It was added together with aa658574bf (commit-graph, fuzz:\nadd fuzzer for commit-graph, 2019-01-15), but as we also declared the\nsame function in \"commit-graph.h\" it wasn't ever needed.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c               | 23 ++++++++++++-----------\n commit-graph.h               |  2 +-\n oss-fuzz/fuzz-commit-graph.c |  6 ++----\n 3 files changed, 15 insertions(+), 16 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 590a6972d2a..50391cc0f32 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -270,9 +270,8 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \t}\n \tgraph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);\n \tclose(fd);\n-\tprepare_repo_settings(r);\n-\tret = parse_commit_graph(&r->settings, graph_map, graph_size);\n \n+\tret = parse_commit_graph(r, graph_map, graph_size);\n \tif (ret)\n \t\tret->odb_source = source;\n \telse\n@@ -372,7 +371,7 @@ static int graph_read_bloom_data(const unsigned char *chunk_start,\n \treturn 0;\n }\n \n-struct commit_graph *parse_commit_graph(struct repo_settings *s,\n+struct commit_graph *parse_commit_graph(struct repository *r,\n \t\t\t\t\tvoid *graph_map, size_t graph_size)\n {\n \tconst unsigned char *data;\n@@ -384,7 +383,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \tif (!graph_map)\n \t\treturn NULL;\n \n-\tif (graph_size < graph_min_size(the_hash_algo))\n+\tif (graph_size < graph_min_size(r->hash_algo))\n \t\treturn NULL;\n \n \tdata = (const unsigned char *)graph_map;\n@@ -404,22 +403,22 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t}\n \n \thash_version = *(unsigned char*)(data + 5);\n-\tif (hash_version != oid_version(the_hash_algo)) {\n+\tif (hash_version != oid_version(r->hash_algo)) {\n \t\terror(_(\"commit-graph hash version %X does not match version %X\"),\n-\t\t      hash_version, oid_version(the_hash_algo));\n+\t\t      hash_version, oid_version(r->hash_algo));\n \t\treturn NULL;\n \t}\n \n \tgraph = alloc_commit_graph();\n \n-\tgraph->hash_algo = the_hash_algo;\n+\tgraph->hash_algo = r->hash_algo;\n \tgraph->num_chunks = *(unsigned char*)(data + 6);\n \tgraph->data = graph_map;\n \tgraph->data_len = graph_size;\n \n \tif (graph_size < GRAPH_HEADER_SIZE +\n \t\t\t (graph->num_chunks + 1) * CHUNK_TOC_ENTRY_SIZE +\n-\t\t\t GRAPH_FANOUT_SIZE + the_hash_algo->rawsz) {\n+\t\t\t GRAPH_FANOUT_SIZE + r->hash_algo->rawsz) {\n \t\terror(_(\"commit-graph file is too small to hold %u chunks\"),\n \t\t      graph->num_chunks);\n \t\tfree(graph);\n@@ -450,7 +449,9 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \tpair_chunk(cf, GRAPH_CHUNKID_BASE, &graph->chunk_base_graphs,\n \t\t   &graph->chunk_base_graphs_size);\n \n-\tif (s->commit_graph_generation_version >= 2) {\n+\tprepare_repo_settings(r);\n+\n+\tif (r->settings.commit_graph_generation_version >= 2) {\n \t\tread_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,\n \t\t\t   graph_read_generation_data, graph);\n \t\tpair_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW,\n@@ -461,7 +462,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t\t\tgraph->read_generation_data = 1;\n \t}\n \n-\tif (s->commit_graph_changed_paths_version) {\n+\tif (r->settings.commit_graph_changed_paths_version) {\n \t\tread_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES,\n \t\t\t   graph_read_bloom_index, graph);\n \t\tread_chunk(cf, GRAPH_CHUNKID_BLOOMDATA,\n@@ -478,7 +479,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t}\n \n \toidread(&graph->oid, graph->data + graph->data_len - graph->hash_algo->rawsz,\n-\t\tthe_repository->hash_algo);\n+\t\tr->hash_algo);\n \n \tfree_chunkfile(cf);\n \treturn graph;\ndiff --git a/commit-graph.h b/commit-graph.h\nindex f20d28ff3a0..5a5c876af0b 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -128,7 +128,7 @@ struct repo_settings;\n  * Callers should initialize the repo_settings with prepare_repo_settings()\n  * prior to calling parse_commit_graph().\n  */\n-struct commit_graph *parse_commit_graph(struct repo_settings *s,\n+struct commit_graph *parse_commit_graph(struct repository *r,\n \t\t\t\t\tvoid *graph_map, size_t graph_size);\n \n /*\ndiff --git a/oss-fuzz/fuzz-commit-graph.c b/oss-fuzz/fuzz-commit-graph.c\nindex fbb77fec197..fb8b8787a46 100644\n--- a/oss-fuzz/fuzz-commit-graph.c\n+++ b/oss-fuzz/fuzz-commit-graph.c\n@@ -4,9 +4,6 @@\n #include \"commit-graph.h\"\n #include \"repository.h\"\n \n-struct commit_graph *parse_commit_graph(struct repo_settings *s,\n-\t\t\t\t\tvoid *graph_map, size_t graph_size);\n-\n int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n \n int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n@@ -22,9 +19,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n \t * possible.\n \t */\n \trepo_set_hash_algo(the_repository, GIT_HASH_SHA1);\n+\tthe_repository->settings.initialized = 1;\n \tthe_repository->settings.commit_graph_generation_version = 2;\n \tthe_repository->settings.commit_graph_changed_paths_version = 1;\n-\tg = parse_commit_graph(&the_repository->settings, (void *)data, size);\n+\tg = parse_commit_graph(the_repository, (void *)data, size);\n \trepo_clear(the_repository);\n \tfree_commit_graph(g);\n \n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523650","messageId":"20250806-b4-pks-commit-graph-wo-the-repository-v2-8-911bae638e61@pks.im","threadId":"63902","inReplyTo":"20250806-b4-pks-commit-graph-wo-the-repository-v2-0-911bae638e61@pks.im","subject":"[PATCH v2 08/10] commit-graph: stop using `the_hash_algo`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T12:00:13Z","receivedAt":"2025-08-06T12:00:46Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Stop using `the_hash_algo` as it implicitly relies on `the_repository`.\nInstead, we either use the hash algo provided via the context or, if\nthere is no such hash algo, we use `the_repository` explicitly. Such\nuses will be removed in subsequent commits.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit-graph.c |  3 ++-\n commit-graph.c         | 27 ++++++++++++++-------------\n commit-graph.h         |  3 ++-\n 3 files changed, 18 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/commit-graph.c b/builtin/commit-graph.c\nindex 145802afb7..680b03a83a 100644\n--- a/builtin/commit-graph.c\n+++ b/builtin/commit-graph.c\n@@ -108,7 +108,8 @@ static int graph_verify(int argc, const char **argv, const char *prefix,\n \t\topened = OPENED_GRAPH;\n \telse if (errno != ENOENT)\n \t\tdie_errno(_(\"Could not open commit-graph '%s'\"), graph_name);\n-\telse if (open_commit_graph_chain(chain_name, &fd, &st))\n+\telse if (open_commit_graph_chain(chain_name, &fd, &st,\n+\t\t\t\t\t the_repository->hash_algo))\n \t\topened = OPENED_CHAIN;\n \telse if (errno != ENOENT)\n \t\tdie_errno(_(\"could not open commit-graph chain '%s'\"), chain_name);\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 50391cc0f3..d351ea5806 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -263,7 +263,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \n \tgraph_size = xsize_t(st->st_size);\n \n-\tif (graph_size < graph_min_size(the_hash_algo)) {\n+\tif (graph_size < graph_min_size(r->hash_algo)) {\n \t\tclose(fd);\n \t\terror(_(\"commit-graph file is too small\"));\n \t\treturn NULL;\n@@ -318,7 +318,7 @@ static int graph_read_commit_data(const unsigned char *chunk_start,\n \t\t\t\t  size_t chunk_size, void *data)\n {\n \tstruct commit_graph *g = data;\n-\tif (chunk_size / graph_data_width(the_hash_algo) != g->num_commits)\n+\tif (chunk_size / graph_data_width(g->hash_algo) != g->num_commits)\n \t\treturn error(_(\"commit-graph commit data chunk is wrong size\"));\n \tg->chunk_commit_data = chunk_start;\n \treturn 0;\n@@ -619,7 +619,8 @@ static int add_graph_to_chain(struct commit_graph *g,\n }\n \n int open_commit_graph_chain(const char *chain_file,\n-\t\t\t    int *fd, struct stat *st)\n+\t\t\t    int *fd, struct stat *st,\n+\t\t\t    const struct git_hash_algo *hash_algo)\n {\n \t*fd = git_open(chain_file);\n \tif (*fd < 0)\n@@ -628,7 +629,7 @@ int open_commit_graph_chain(const char *chain_file,\n \t\tclose(*fd);\n \t\treturn 0;\n \t}\n-\tif (st->st_size < (ssize_t) the_hash_algo->hexsz) {\n+\tif (st->st_size < (ssize_t) hash_algo->hexsz) {\n \t\tclose(*fd);\n \t\tif (!st->st_size) {\n \t\t\t/* treat empty files the same as missing */\n@@ -653,7 +654,7 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \tFILE *fp = xfdopen(fd, \"r\");\n \tsize_t count;\n \n-\tcount = st->st_size / (the_hash_algo->hexsz + 1);\n+\tcount = st->st_size / (r->hash_algo->hexsz + 1);\n \tCALLOC_ARRAY(oids, count);\n \n \todb_prepare_alternates(r->objects);\n@@ -715,7 +716,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,\n \tint fd;\n \tstruct commit_graph *g = NULL;\n \n-\tif (open_commit_graph_chain(chain_file, &fd, &st)) {\n+\tif (open_commit_graph_chain(chain_file, &fd, &st, r->hash_algo)) {\n \t\tint incomplete;\n \t\t/* ownership of fd is taken over by load function */\n \t\tg = load_commit_graph_chain_fd_st(r, fd, &st, &incomplete);\n@@ -907,7 +908,7 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \t\tdie(_(\"invalid commit position. commit-graph is likely corrupt\"));\n \n \tlex_index = pos - g->num_commits_in_base;\n-\tcommit_data = g->chunk_commit_data + st_mult(graph_data_width(the_hash_algo), lex_index);\n+\tcommit_data = g->chunk_commit_data + st_mult(graph_data_width(g->hash_algo), lex_index);\n \n \tgraph_data = commit_graph_data_at(item);\n \tgraph_data->graph_pos = pos;\n@@ -1111,7 +1112,7 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\tg = g->base_graph;\n \n \tcommit_data = g->chunk_commit_data +\n-\t\t\tst_mult(graph_data_width(the_hash_algo),\n+\t\t\tst_mult(graph_data_width(g->hash_algo),\n \t\t\t\tgraph_pos - g->num_commits_in_base);\n \n \toidread(&oid, commit_data, the_repository->hash_algo);\n@@ -1221,7 +1222,7 @@ static int write_graph_chunk_oids(struct hashfile *f,\n \n \tfor (count = 0; count < ctx->commits.nr; count++, list++) {\n \t\tdisplay_progress(ctx->progress, ++ctx->progress_cnt);\n-\t\thashwrite(f, (*list)->object.oid.hash, the_hash_algo->rawsz);\n+\t\thashwrite(f, (*list)->object.oid.hash, f->algop->rawsz);\n \t}\n \n \treturn 0;\n@@ -1252,7 +1253,7 @@ static int write_graph_chunk_data(struct hashfile *f,\n \t\t\tdie(_(\"unable to parse commit %s\"),\n \t\t\t\toid_to_hex(&(*list)->object.oid));\n \t\ttree = get_commit_tree_oid(*list);\n-\t\thashwrite(f, tree->hash, the_hash_algo->rawsz);\n+\t\thashwrite(f, tree->hash, ctx->r->hash_algo->rawsz);\n \n \t\tparent = (*list)->parents;\n \n@@ -2034,7 +2035,7 @@ static size_t write_graph_chunk_base_1(struct hashfile *f,\n \t\treturn 0;\n \n \tnum = write_graph_chunk_base_1(f, g->base_graph);\n-\thashwrite(f, g->oid.hash, the_hash_algo->rawsz);\n+\thashwrite(f, g->oid.hash, g->hash_algo->rawsz);\n \treturn num + 1;\n }\n \n@@ -2058,7 +2059,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \tstruct hashfile *f;\n \tstruct tempfile *graph_layer; /* when ctx->split is non-zero */\n \tstruct lock_file lk = LOCK_INIT;\n-\tconst unsigned hashsz = the_hash_algo->rawsz;\n+\tconst unsigned hashsz = ctx->r->hash_algo->rawsz;\n \tstruct strbuf progress_title = STRBUF_INIT;\n \tstruct chunkfile *cf;\n \tunsigned char file_hash[GIT_MAX_RAWSZ];\n@@ -2146,7 +2147,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \thashwrite_be32(f, GRAPH_SIGNATURE);\n \n \thashwrite_u8(f, GRAPH_VERSION);\n-\thashwrite_u8(f, oid_version(the_hash_algo));\n+\thashwrite_u8(f, oid_version(ctx->r->hash_algo));\n \thashwrite_u8(f, get_num_chunks(cf));\n \thashwrite_u8(f, ctx->num_commit_graphs_after - 1);\n \ndiff --git a/commit-graph.h b/commit-graph.h\nindex 5a5c876af0..6de624785c 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -32,7 +32,8 @@ struct string_list;\n char *get_commit_graph_filename(struct odb_source *source);\n char *get_commit_graph_chain_filename(struct odb_source *source);\n int open_commit_graph(const char *graph_file, int *fd, struct stat *st);\n-int open_commit_graph_chain(const char *chain_file, int *fd, struct stat *st);\n+int open_commit_graph_chain(const char *chain_file, int *fd, struct stat *st,\n+\t\t\t    const struct git_hash_algo *hash_algo);\n \n /*\n  * Given a commit struct, try to fill the commit struct info, including:\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523651","messageId":"20250806-b4-pks-commit-graph-wo-the-repository-v2-9-911bae638e61@pks.im","threadId":"63902","inReplyTo":"20250806-b4-pks-commit-graph-wo-the-repository-v2-0-911bae638e61@pks.im","subject":"[PATCH v2 09/10] commit-graph: stop using `the_repository`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T12:00:14Z","receivedAt":"2025-08-06T12:00:49Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"There's still a bunch of uses of `the_repository` in \"commit-graph.c\",\nwhich we want to stop using due to it being a global variable. Refactor\nthe code to stop using `the_repository` in favor of the repository\nprovided via the calling context.\n\nThis allows us to drop the `USE_THE_REPOSITORY_VARIABLE` macro.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit.c |  2 +-\n builtin/merge.c  |  2 +-\n commit-graph.c   | 77 ++++++++++++++++++++++++++++----------------------------\n commit-graph.h   |  2 +-\n 4 files changed, 42 insertions(+), 41 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 63e7158e98..8ca0aede48 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1933,7 +1933,7 @@ int cmd_commit(int argc,\n \t\t      \"new index file. Check that disk is not full and quota is\\n\"\n \t\t      \"not exceeded, and then \\\"git restore --staged :/\\\" to recover.\"));\n \n-\tgit_test_write_commit_graph_or_die();\n+\tgit_test_write_commit_graph_or_die(the_repository->objects->sources);\n \n \trepo_rerere(the_repository, 0);\n \trun_auto_maintenance(quiet);\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 18b22c0a26..263cb58471 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1862,7 +1862,7 @@ int cmd_merge(int argc,\n \tif (squash) {\n \t\tfinish(head_commit, remoteheads, NULL, NULL);\n \n-\t\tgit_test_write_commit_graph_or_die();\n+\t\tgit_test_write_commit_graph_or_die(the_repository->objects->sources);\n \t} else\n \t\twrite_merge_state(remoteheads);\n \ndiff --git a/commit-graph.c b/commit-graph.c\nindex d351ea5806..35143c356c 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -1,5 +1,3 @@\n-#define USE_THE_REPOSITORY_VARIABLE\n-\n #include \"git-compat-util.h\"\n #include \"config.h\"\n #include \"csum-file.h\"\n@@ -27,7 +25,7 @@\n #include \"tree.h\"\n #include \"chunk-format.h\"\n \n-void git_test_write_commit_graph_or_die(void)\n+void git_test_write_commit_graph_or_die(struct odb_source *source)\n {\n \tint flags = 0;\n \tif (!git_env_bool(GIT_TEST_COMMIT_GRAPH, 0))\n@@ -36,8 +34,7 @@ void git_test_write_commit_graph_or_die(void)\n \tif (git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0))\n \t\tflags = COMMIT_GRAPH_WRITE_BLOOM_FILTERS;\n \n-\tif (write_commit_graph_reachable(the_repository->objects->sources,\n-\t\t\t\t\t flags, NULL))\n+\tif (write_commit_graph_reachable(source, flags, NULL))\n \t\tdie(\"failed to write commit-graph under GIT_TEST_COMMIT_GRAPH\");\n }\n \n@@ -595,7 +592,7 @@ static int add_graph_to_chain(struct commit_graph *g,\n \t\tif (!cur_g ||\n \t\t    !oideq(&oids[n], &cur_g->oid) ||\n \t\t    !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_algo->rawsz, n),\n-\t\t\t    the_repository->hash_algo)) {\n+\t\t\t    g->hash_algo)) {\n \t\t\twarning(_(\"commit-graph chain does not match\"));\n \t\t\treturn 0;\n \t\t}\n@@ -665,7 +662,7 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \t\tif (strbuf_getline_lf(&line, fp) == EOF)\n \t\t\tbreak;\n \n-\t\tif (get_oid_hex(line.buf, &oids[i])) {\n+\t\tif (get_oid_hex_algop(line.buf, &oids[i], r->hash_algo)) {\n \t\t\twarning(_(\"invalid commit-graph chain: line '%s' not a hash\"),\n \t\t\t\tline.buf);\n \t\t\tvalid = 0;\n@@ -751,7 +748,7 @@ static void prepare_commit_graph_one(struct repository *r,\n  * Return 1 if commit_graph is non-NULL, and 0 otherwise.\n  *\n  * On the first invocation, this function attempts to load the commit\n- * graph if the_repository is configured to have one.\n+ * graph if the repository is configured to have one.\n  */\n static int prepare_commit_graph(struct repository *r)\n {\n@@ -872,7 +869,7 @@ static void load_oid_from_graph(struct commit_graph *g,\n \tlex_index = pos - g->num_commits_in_base;\n \n \toidread(oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, lex_index),\n-\t\tthe_repository->hash_algo);\n+\t\tg->hash_algo);\n }\n \n static struct commit_list **insert_parent_or_die(struct repository *r,\n@@ -1115,7 +1112,7 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\t\tst_mult(graph_data_width(g->hash_algo),\n \t\t\t\tgraph_pos - g->num_commits_in_base);\n \n-\toidread(&oid, commit_data, the_repository->hash_algo);\n+\toidread(&oid, commit_data, g->hash_algo);\n \tset_commit_tree(c, lookup_tree(r, &oid));\n \n \treturn c->maybe_tree;\n@@ -1543,7 +1540,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Loading known commits in commit graph\"),\n \t\t\t\t\tctx->oids.nr);\n \tfor (i = 0; i < ctx->oids.nr; i++) {\n@@ -1561,7 +1558,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)\n \t */\n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Expanding reachable commits in commit graph\"),\n \t\t\t\t\t0);\n \tfor (i = 0; i < ctx->oids.nr; i++) {\n@@ -1582,7 +1579,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Clearing commit marks in commit graph\"),\n \t\t\t\t\tctx->oids.nr);\n \tfor (i = 0; i < ctx->oids.nr; i++) {\n@@ -1699,7 +1696,7 @@ static void compute_topological_levels(struct write_commit_graph_context *ctx)\n \tif (ctx->report_progress)\n \t\tinfo.progress = ctx->progress\n \t\t\t      = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Computing commit graph topological levels\"),\n \t\t\t\t\tctx->commits.nr);\n \n@@ -1734,7 +1731,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)\n \tif (ctx->report_progress)\n \t\tinfo.progress = ctx->progress\n \t\t\t      = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Computing commit graph generation numbers\"),\n \t\t\t\t\tctx->commits.nr);\n \n@@ -1811,7 +1808,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tprogress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\t_(\"Computing commit changed paths Bloom filters\"),\n \t\t\tctx->commits.nr);\n \n@@ -1857,6 +1854,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n }\n \n struct refs_cb_data {\n+\tstruct repository *repo;\n \tstruct oidset *commits;\n \tstruct progress *progress;\n };\n@@ -1869,9 +1867,9 @@ static int add_ref_to_set(const char *refname UNUSED,\n \tstruct object_id peeled;\n \tstruct refs_cb_data *data = (struct refs_cb_data *)cb_data;\n \n-\tif (!peel_iterated_oid(the_repository, oid, &peeled))\n+\tif (!peel_iterated_oid(data->repo, oid, &peeled))\n \t\toid = &peeled;\n-\tif (odb_read_object_info(the_repository->objects, oid, NULL) == OBJ_COMMIT)\n+\tif (odb_read_object_info(data->repo->objects, oid, NULL) == OBJ_COMMIT)\n \t\toidset_insert(data->commits, oid);\n \n \tdisplay_progress(data->progress, oidset_size(data->commits));\n@@ -1888,13 +1886,15 @@ int write_commit_graph_reachable(struct odb_source *source,\n \tint result;\n \n \tmemset(&data, 0, sizeof(data));\n+\tdata.repo = source->odb->repo;\n \tdata.commits = &commits;\n+\n \tif (flags & COMMIT_GRAPH_WRITE_PROGRESS)\n \t\tdata.progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tsource->odb->repo,\n \t\t\t_(\"Collecting referenced commits\"), 0);\n \n-\trefs_for_each_ref(get_main_ref_store(the_repository), add_ref_to_set,\n+\trefs_for_each_ref(get_main_ref_store(source->odb->repo), add_ref_to_set,\n \t\t\t  &data);\n \n \tstop_progress(&data.progress);\n@@ -1923,7 +1923,7 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx,\n \t\t\t       \"Finding commits for commit graph in %\"PRIuMAX\" packs\",\n \t\t\t       pack_indexes->nr),\n \t\t\t    (uintmax_t)pack_indexes->nr);\n-\t\tctx->progress = start_delayed_progress(the_repository,\n+\t\tctx->progress = start_delayed_progress(ctx->r,\n \t\t\t\t\t\t       progress_title.buf, 0);\n \t\tctx->progress_done = 0;\n \t}\n@@ -1977,7 +1977,7 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)\n {\n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\t_(\"Finding commits for commit graph among packed objects\"),\n \t\t\tctx->approx_nr_objects);\n \tfor_each_packed_object(ctx->r, add_packed_commits, ctx,\n@@ -1996,7 +1996,7 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx)\n \tctx->num_extra_edges = 0;\n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\t_(\"Finding extra edges in commit graph\"),\n \t\t\tctx->oids.nr);\n \toid_array_sort(&ctx->oids);\n@@ -2075,7 +2075,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\tctx->graph_name = get_commit_graph_filename(ctx->odb_source);\n \t}\n \n-\tif (safe_create_leading_directories(the_repository, ctx->graph_name)) {\n+\tif (safe_create_leading_directories(ctx->r, ctx->graph_name)) {\n \t\terror(_(\"unable to create leading directories of %s\"),\n \t\t\tctx->graph_name);\n \t\treturn -1;\n@@ -2094,18 +2094,18 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\t\treturn -1;\n \t\t}\n \n-\t\tif (adjust_shared_perm(the_repository, get_tempfile_path(graph_layer))) {\n+\t\tif (adjust_shared_perm(ctx->r, get_tempfile_path(graph_layer))) {\n \t\t\terror(_(\"unable to adjust shared permissions for '%s'\"),\n \t\t\t      get_tempfile_path(graph_layer));\n \t\t\treturn -1;\n \t\t}\n \n-\t\tf = hashfd(the_repository->hash_algo,\n+\t\tf = hashfd(ctx->r->hash_algo,\n \t\t\t   get_tempfile_fd(graph_layer), get_tempfile_path(graph_layer));\n \t} else {\n \t\thold_lock_file_for_update_mode(&lk, ctx->graph_name,\n \t\t\t\t\t       LOCK_DIE_ON_ERROR, 0444);\n-\t\tf = hashfd(the_repository->hash_algo,\n+\t\tf = hashfd(ctx->r->hash_algo,\n \t\t\t   get_lock_file_fd(&lk), get_lock_file_path(&lk));\n \t}\n \n@@ -2158,7 +2158,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\t\t       get_num_chunks(cf)),\n \t\t\t    get_num_chunks(cf));\n \t\tctx->progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\tprogress_title.buf,\n \t\t\tst_mult(get_num_chunks(cf), ctx->commits.nr));\n \t}\n@@ -2216,7 +2216,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\t}\n \n \t\tfree(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);\n-\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(hash_to_hex(file_hash));\n+\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] =\n+\t\t\txstrdup(hash_to_hex_algop(file_hash, ctx->r->hash_algo));\n \t\tfinal_graph_name = get_split_graph_filename(ctx->odb_source,\n \t\t\t\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);\n \t\tfree(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1]);\n@@ -2370,7 +2371,7 @@ static void sort_and_scan_merged_commits(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Scanning merged commits\"),\n \t\t\t\t\tctx->commits.nr);\n \n@@ -2415,7 +2416,7 @@ static void merge_commit_graphs(struct write_commit_graph_context *ctx)\n \t\tcurrent_graph_number--;\n \n \t\tif (ctx->report_progress)\n-\t\t\tctx->progress = start_delayed_progress(the_repository,\n+\t\t\tctx->progress = start_delayed_progress(ctx->r,\n \t\t\t\t\t\t\t       _(\"Merging commit-graph\"), 0);\n \n \t\tmerge_commit_graph(ctx, g);\n@@ -2518,7 +2519,7 @@ int write_commit_graph(struct odb_source *source,\n \t\t       enum commit_graph_write_flags flags,\n \t\t       const struct commit_graph_opts *opts)\n {\n-\tstruct repository *r = the_repository;\n+\tstruct repository *r = source->odb->repo;\n \tstruct write_commit_graph_context ctx = {\n \t\t.r = r,\n \t\t.odb_source = source,\n@@ -2618,14 +2619,14 @@ int write_commit_graph(struct odb_source *source,\n \t\t\treplace = ctx.opts->split_flags & COMMIT_GRAPH_SPLIT_REPLACE;\n \t}\n \n-\tctx.approx_nr_objects = repo_approximate_object_count(the_repository);\n+\tctx.approx_nr_objects = repo_approximate_object_count(r);\n \n \tif (ctx.append && ctx.r->objects->commit_graph) {\n \t\tstruct commit_graph *g = ctx.r->objects->commit_graph;\n \t\tfor (i = 0; i < g->num_commits; i++) {\n \t\t\tstruct object_id oid;\n \t\t\toidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n-\t\t\t\tthe_repository->hash_algo);\n+\t\t\t\tr->hash_algo);\n \t\t\toid_array_append(&ctx.oids, &oid);\n \t\t}\n \t}\n@@ -2733,7 +2734,7 @@ static void graph_report(const char *fmt, ...)\n \n static int commit_graph_checksum_valid(struct commit_graph *g)\n {\n-\treturn hashfile_checksum_valid(the_repository->hash_algo,\n+\treturn hashfile_checksum_valid(g->hash_algo,\n \t\t\t\t       g->data, g->data_len);\n }\n \n@@ -2756,7 +2757,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\tstruct commit *graph_commit;\n \n \t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n-\t\t\tthe_repository->hash_algo);\n+\t\t\tg->hash_algo);\n \n \t\tif (i && oidcmp(&prev_oid, &cur_oid) >= 0)\n \t\t\tgraph_report(_(\"commit-graph has incorrect OID order: %s then %s\"),\n@@ -2801,7 +2802,7 @@ static int verify_one_commit_graph(struct repository *r,\n \n \t\tdisplay_progress(progress, ++(*seen));\n \t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n-\t\t\tthe_repository->hash_algo);\n+\t\t\tg->hash_algo);\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\n \t\todb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r));\n@@ -2905,7 +2906,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n \t\tif (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW))\n \t\t\ttotal += g->num_commits_in_base;\n \n-\t\tprogress = start_progress(the_repository,\n+\t\tprogress = start_progress(r,\n \t\t\t\t\t  _(\"Verifying commits in commit graph\"),\n \t\t\t\t\t  total);\n \t}\ndiff --git a/commit-graph.h b/commit-graph.h\nindex 6de624785c..a2471e9bdc 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -21,7 +21,7 @@\n  * call this method oustide of a builtin, and only if you know what\n  * you are doing!\n  */\n-void git_test_write_commit_graph_or_die(void);\n+void git_test_write_commit_graph_or_die(struct odb_source *source);\n \n struct commit;\n struct bloom_filter_settings;\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523652","messageId":"20250806-b4-pks-commit-graph-wo-the-repository-v2-10-911bae638e61@pks.im","threadId":"63902","inReplyTo":"20250806-b4-pks-commit-graph-wo-the-repository-v2-0-911bae638e61@pks.im","subject":"[PATCH v2 10/10] commit-graph: stop passing in redundant repository","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-06T12:00:15Z","receivedAt":"2025-08-06T12:00:52Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Many of the commit-graph related functions take in both a repository and\nthe object database source (directly or via `struct commit_graph`) for\nwhich we are supposed to load such a commit-graph. In the best case this\ninformation is simply redundant as the source already contains a\nreference to its owning object database, which in turn has a reference\nto its repository. In the worst case this information could even\nmismatch when passing in a source that doesn't belong to the same\nrepository.\n\nRefactor the code so that we only pass in the object database source in\nthose cases.\n\nThere is one exception though, namely `load_commit_graph_chain_fd_st()`,\nwhich is responsible for loading a commit-graph chain. It is expected\nthat parts of the commit-graph chain aren't located in the same object\nsource as the chain file itself, but in a different one. Consequently,\nthis function doesn't work on the source level but on the database level\ninstead.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit-graph.c     |   6 +--\n commit-graph.c             | 120 +++++++++++++++++++--------------------------\n commit-graph.h             |  12 ++---\n t/helper/test-read-graph.c |   2 +-\n 4 files changed, 59 insertions(+), 81 deletions(-)\n\ndiff --git a/builtin/commit-graph.c b/builtin/commit-graph.c\nindex 680b03a83a..1b80993b2d 100644\n--- a/builtin/commit-graph.c\n+++ b/builtin/commit-graph.c\n@@ -121,15 +121,15 @@ static int graph_verify(int argc, const char **argv, const char *prefix,\n \tif (opened == OPENED_NONE)\n \t\treturn 0;\n \telse if (opened == OPENED_GRAPH)\n-\t\tgraph = load_commit_graph_one_fd_st(the_repository, fd, &st, source);\n+\t\tgraph = load_commit_graph_one_fd_st(source, fd, &st);\n \telse\n-\t\tgraph = load_commit_graph_chain_fd_st(the_repository, fd, &st,\n+\t\tgraph = load_commit_graph_chain_fd_st(the_repository->objects, fd, &st,\n \t\t\t\t\t\t      &incomplete_chain);\n \n \tif (!graph)\n \t\treturn 1;\n \n-\tret = verify_commit_graph(the_repository, graph, flags);\n+\tret = verify_commit_graph(graph, flags);\n \tfree_commit_graph(graph);\n \n \tif (incomplete_chain) {\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 35143c356c..e2e70ea4f6 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -250,9 +250,8 @@ int open_commit_graph(const char *graph_file, int *fd, struct stat *st)\n \treturn 1;\n }\n \n-struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n-\t\t\t\t\t\t int fd, struct stat *st,\n-\t\t\t\t\t\t struct odb_source *source)\n+struct commit_graph *load_commit_graph_one_fd_st(struct odb_source *source,\n+\t\t\t\t\t\t int fd, struct stat *st)\n {\n \tvoid *graph_map;\n \tsize_t graph_size;\n@@ -260,7 +259,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \n \tgraph_size = xsize_t(st->st_size);\n \n-\tif (graph_size < graph_min_size(r->hash_algo)) {\n+\tif (graph_size < graph_min_size(source->odb->repo->hash_algo)) {\n \t\tclose(fd);\n \t\terror(_(\"commit-graph file is too small\"));\n \t\treturn NULL;\n@@ -268,7 +267,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \tgraph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);\n \tclose(fd);\n \n-\tret = parse_commit_graph(r, graph_map, graph_size);\n+\tret = parse_commit_graph(source->odb->repo, graph_map, graph_size);\n \tif (ret)\n \t\tret->odb_source = source;\n \telse\n@@ -488,11 +487,9 @@ struct commit_graph *parse_commit_graph(struct repository *r,\n \treturn NULL;\n }\n \n-static struct commit_graph *load_commit_graph_one(struct repository *r,\n-\t\t\t\t\t\t  const char *graph_file,\n-\t\t\t\t\t\t  struct odb_source *source)\n+static struct commit_graph *load_commit_graph_one(struct odb_source *source,\n+\t\t\t\t\t\t  const char *graph_file)\n {\n-\n \tstruct stat st;\n \tint fd;\n \tstruct commit_graph *g;\n@@ -501,19 +498,17 @@ static struct commit_graph *load_commit_graph_one(struct repository *r,\n \tif (!open_ok)\n \t\treturn NULL;\n \n-\tg = load_commit_graph_one_fd_st(r, fd, &st, source);\n-\n+\tg = load_commit_graph_one_fd_st(source, fd, &st);\n \tif (g)\n \t\tg->filename = xstrdup(graph_file);\n \n \treturn g;\n }\n \n-static struct commit_graph *load_commit_graph_v1(struct repository *r,\n-\t\t\t\t\t\t struct odb_source *source)\n+static struct commit_graph *load_commit_graph_v1(struct odb_source *source)\n {\n \tchar *graph_name = get_commit_graph_filename(source);\n-\tstruct commit_graph *g = load_commit_graph_one(r, graph_name, source);\n+\tstruct commit_graph *g = load_commit_graph_one(source, graph_name);\n \tfree(graph_name);\n \n \treturn g;\n@@ -640,7 +635,7 @@ int open_commit_graph_chain(const char *chain_file,\n \treturn 1;\n }\n \n-struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n+struct commit_graph *load_commit_graph_chain_fd_st(struct object_database *odb,\n \t\t\t\t\t\t   int fd, struct stat *st,\n \t\t\t\t\t\t   int *incomplete_chain)\n {\n@@ -651,10 +646,10 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \tFILE *fp = xfdopen(fd, \"r\");\n \tsize_t count;\n \n-\tcount = st->st_size / (r->hash_algo->hexsz + 1);\n+\tcount = st->st_size / (odb->repo->hash_algo->hexsz + 1);\n \tCALLOC_ARRAY(oids, count);\n \n-\todb_prepare_alternates(r->objects);\n+\todb_prepare_alternates(odb);\n \n \tfor (size_t i = 0; i < count; i++) {\n \t\tstruct odb_source *source;\n@@ -662,7 +657,7 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \t\tif (strbuf_getline_lf(&line, fp) == EOF)\n \t\t\tbreak;\n \n-\t\tif (get_oid_hex_algop(line.buf, &oids[i], r->hash_algo)) {\n+\t\tif (get_oid_hex_algop(line.buf, &oids[i], odb->repo->hash_algo)) {\n \t\t\twarning(_(\"invalid commit-graph chain: line '%s' not a hash\"),\n \t\t\t\tline.buf);\n \t\t\tvalid = 0;\n@@ -670,9 +665,9 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \t\t}\n \n \t\tvalid = 0;\n-\t\tfor (source = r->objects->sources; source; source = source->next) {\n+\t\tfor (source = odb->sources; source; source = source->next) {\n \t\t\tchar *graph_name = get_split_graph_filename(source, line.buf);\n-\t\t\tstruct commit_graph *g = load_commit_graph_one(r, graph_name, source);\n+\t\t\tstruct commit_graph *g = load_commit_graph_one(source, graph_name);\n \n \t\t\tfree(graph_name);\n \n@@ -705,45 +700,33 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \treturn graph_chain;\n }\n \n-static struct commit_graph *load_commit_graph_chain(struct repository *r,\n-\t\t\t\t\t\t    struct odb_source *source)\n+static struct commit_graph *load_commit_graph_chain(struct odb_source *source)\n {\n \tchar *chain_file = get_commit_graph_chain_filename(source);\n \tstruct stat st;\n \tint fd;\n \tstruct commit_graph *g = NULL;\n \n-\tif (open_commit_graph_chain(chain_file, &fd, &st, r->hash_algo)) {\n+\tif (open_commit_graph_chain(chain_file, &fd, &st, source->odb->repo->hash_algo)) {\n \t\tint incomplete;\n \t\t/* ownership of fd is taken over by load function */\n-\t\tg = load_commit_graph_chain_fd_st(r, fd, &st, &incomplete);\n+\t\tg = load_commit_graph_chain_fd_st(source->odb, fd, &st, &incomplete);\n \t}\n \n \tfree(chain_file);\n \treturn g;\n }\n \n-struct commit_graph *read_commit_graph_one(struct repository *r,\n-\t\t\t\t\t   struct odb_source *source)\n+struct commit_graph *read_commit_graph_one(struct odb_source *source)\n {\n-\tstruct commit_graph *g = load_commit_graph_v1(r, source);\n+\tstruct commit_graph *g = load_commit_graph_v1(source);\n \n \tif (!g)\n-\t\tg = load_commit_graph_chain(r, source);\n+\t\tg = load_commit_graph_chain(source);\n \n \treturn g;\n }\n \n-static void prepare_commit_graph_one(struct repository *r,\n-\t\t\t\t     struct odb_source *source)\n-{\n-\n-\tif (r->objects->commit_graph)\n-\t\treturn;\n-\n-\tr->objects->commit_graph = read_commit_graph_one(r, source);\n-}\n-\n /*\n  * Return 1 if commit_graph is non-NULL, and 0 otherwise.\n  *\n@@ -784,10 +767,12 @@ static int prepare_commit_graph(struct repository *r)\n \t\treturn 0;\n \n \todb_prepare_alternates(r->objects);\n-\tfor (source = r->objects->sources;\n-\t     !r->objects->commit_graph && source;\n-\t     source = source->next)\n-\t\tprepare_commit_graph_one(r, source);\n+\tfor (source = r->objects->sources; source; source = source->next) {\n+\t\tr->objects->commit_graph = read_commit_graph_one(source);\n+\t\tif (r->objects->commit_graph)\n+\t\t\tbreak;\n+\t}\n+\n \treturn !!r->objects->commit_graph;\n }\n \n@@ -872,8 +857,7 @@ static void load_oid_from_graph(struct commit_graph *g,\n \t\tg->hash_algo);\n }\n \n-static struct commit_list **insert_parent_or_die(struct repository *r,\n-\t\t\t\t\t\t struct commit_graph *g,\n+static struct commit_list **insert_parent_or_die(struct commit_graph *g,\n \t\t\t\t\t\t uint32_t pos,\n \t\t\t\t\t\t struct commit_list **pptr)\n {\n@@ -884,7 +868,7 @@ static struct commit_list **insert_parent_or_die(struct repository *r,\n \t\tdie(\"invalid parent position %\"PRIu32, pos);\n \n \tload_oid_from_graph(g, pos, &oid);\n-\tc = lookup_commit(r, &oid);\n+\tc = lookup_commit(g->odb_source->odb->repo, &oid);\n \tif (!c)\n \t\tdie(_(\"could not find commit %s\"), oid_to_hex(&oid));\n \tcommit_graph_data_at(c)->graph_pos = pos;\n@@ -940,8 +924,7 @@ static inline void set_commit_tree(struct commit *c, struct tree *t)\n \tc->maybe_tree = t;\n }\n \n-static int fill_commit_in_graph(struct repository *r,\n-\t\t\t\tstruct commit *item,\n+static int fill_commit_in_graph(struct commit *item,\n \t\t\t\tstruct commit_graph *g, uint32_t pos)\n {\n \tuint32_t edge_value;\n@@ -967,13 +950,13 @@ static int fill_commit_in_graph(struct repository *r,\n \tedge_value = get_be32(commit_data + g->hash_algo->rawsz);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n-\tpptr = insert_parent_or_die(r, g, edge_value, pptr);\n+\tpptr = insert_parent_or_die(g, edge_value, pptr);\n \n \tedge_value = get_be32(commit_data + g->hash_algo->rawsz + 4);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n \tif (!(edge_value & GRAPH_EXTRA_EDGES_NEEDED)) {\n-\t\tpptr = insert_parent_or_die(r, g, edge_value, pptr);\n+\t\tpptr = insert_parent_or_die(g, edge_value, pptr);\n \t\treturn 1;\n \t}\n \n@@ -988,7 +971,7 @@ static int fill_commit_in_graph(struct repository *r,\n \t\t}\n \t\tedge_value = get_be32(g->chunk_extra_edges +\n \t\t\t\t      sizeof(uint32_t) * parent_data_pos);\n-\t\tpptr = insert_parent_or_die(r, g,\n+\t\tpptr = insert_parent_or_die(g,\n \t\t\t\t\t    edge_value & GRAPH_EDGE_LAST_MASK,\n \t\t\t\t\t    pptr);\n \t\tparent_data_pos++;\n@@ -1054,14 +1037,13 @@ struct commit *lookup_commit_in_graph(struct repository *repo, const struct obje\n \tif (commit->object.parsed)\n \t\treturn commit;\n \n-\tif (!fill_commit_in_graph(repo, commit, repo->objects->commit_graph, pos))\n+\tif (!fill_commit_in_graph(commit, repo->objects->commit_graph, pos))\n \t\treturn NULL;\n \n \treturn commit;\n }\n \n-static int parse_commit_in_graph_one(struct repository *r,\n-\t\t\t\t     struct commit_graph *g,\n+static int parse_commit_in_graph_one(struct commit_graph *g,\n \t\t\t\t     struct commit *item)\n {\n \tuint32_t pos;\n@@ -1070,7 +1052,7 @@ static int parse_commit_in_graph_one(struct repository *r,\n \t\treturn 1;\n \n \tif (find_commit_pos_in_graph(item, g, &pos))\n-\t\treturn fill_commit_in_graph(r, item, g, pos);\n+\t\treturn fill_commit_in_graph(item, g, pos);\n \n \treturn 0;\n }\n@@ -1087,7 +1069,7 @@ int parse_commit_in_graph(struct repository *r, struct commit *item)\n \n \tif (!prepare_commit_graph(r))\n \t\treturn 0;\n-\treturn parse_commit_in_graph_one(r, r->objects->commit_graph, item);\n+\treturn parse_commit_in_graph_one(r->objects->commit_graph, item);\n }\n \n void load_commit_graph_info(struct repository *r, struct commit *item)\n@@ -1097,8 +1079,7 @@ void load_commit_graph_info(struct repository *r, struct commit *item)\n \t\tfill_commit_graph_info(item, r->objects->commit_graph, pos);\n }\n \n-static struct tree *load_tree_for_commit(struct repository *r,\n-\t\t\t\t\t struct commit_graph *g,\n+static struct tree *load_tree_for_commit(struct commit_graph *g,\n \t\t\t\t\t struct commit *c)\n {\n \tstruct object_id oid;\n@@ -1113,13 +1094,12 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\t\t\tgraph_pos - g->num_commits_in_base);\n \n \toidread(&oid, commit_data, g->hash_algo);\n-\tset_commit_tree(c, lookup_tree(r, &oid));\n+\tset_commit_tree(c, lookup_tree(g->odb_source->odb->repo, &oid));\n \n \treturn c->maybe_tree;\n }\n \n-static struct tree *get_commit_tree_in_graph_one(struct repository *r,\n-\t\t\t\t\t\t struct commit_graph *g,\n+static struct tree *get_commit_tree_in_graph_one(struct commit_graph *g,\n \t\t\t\t\t\t const struct commit *c)\n {\n \tif (c->maybe_tree)\n@@ -1127,12 +1107,12 @@ static struct tree *get_commit_tree_in_graph_one(struct repository *r,\n \tif (commit_graph_position(c) == COMMIT_NOT_FROM_GRAPH)\n \t\tBUG(\"get_commit_tree_in_graph_one called from non-commit-graph commit\");\n \n-\treturn load_tree_for_commit(r, g, (struct commit *)c);\n+\treturn load_tree_for_commit(g, (struct commit *)c);\n }\n \n struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit *c)\n {\n-\treturn get_commit_tree_in_graph_one(r, r->objects->commit_graph, c);\n+\treturn get_commit_tree_in_graph_one(r->objects->commit_graph, c);\n }\n \n struct packed_commit_list {\n@@ -2738,11 +2718,11 @@ static int commit_graph_checksum_valid(struct commit_graph *g)\n \t\t\t\t       g->data, g->data_len);\n }\n \n-static int verify_one_commit_graph(struct repository *r,\n-\t\t\t\t   struct commit_graph *g,\n+static int verify_one_commit_graph(struct commit_graph *g,\n \t\t\t\t   struct progress *progress,\n \t\t\t\t   uint64_t *seen)\n {\n+\tstruct repository *r = g->odb_source->odb->repo;\n \tuint32_t i, cur_fanout_pos = 0;\n \tstruct object_id prev_oid, cur_oid;\n \tstruct commit *seen_gen_zero = NULL;\n@@ -2776,7 +2756,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\t}\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\n-\t\tif (!parse_commit_in_graph_one(r, g, graph_commit))\n+\t\tif (!parse_commit_in_graph_one(g, graph_commit))\n \t\t\tgraph_report(_(\"failed to parse commit %s from commit-graph\"),\n \t\t\t\t     oid_to_hex(&cur_oid));\n \t}\n@@ -2812,7 +2792,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\t\tcontinue;\n \t\t}\n \n-\t\tif (!oideq(&get_commit_tree_in_graph_one(r, g, graph_commit)->object.oid,\n+\t\tif (!oideq(&get_commit_tree_in_graph_one(g, graph_commit)->object.oid,\n \t\t\t   get_commit_tree_oid(odb_commit)))\n \t\t\tgraph_report(_(\"root tree OID for commit %s in commit-graph is %s != %s\"),\n \t\t\t\t     oid_to_hex(&cur_oid),\n@@ -2830,7 +2810,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\t\t}\n \n \t\t\t/* parse parent in case it is in a base graph */\n-\t\t\tparse_commit_in_graph_one(r, g, graph_parents->item);\n+\t\t\tparse_commit_in_graph_one(g, graph_parents->item);\n \n \t\t\tif (!oideq(&graph_parents->item->object.oid, &odb_parents->item->object.oid))\n \t\t\t\tgraph_report(_(\"commit-graph parent for %s is %s != %s\"),\n@@ -2890,7 +2870,7 @@ static int verify_one_commit_graph(struct repository *r,\n \treturn verify_commit_graph_error;\n }\n \n-int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n+int verify_commit_graph(struct commit_graph *g, int flags)\n {\n \tstruct progress *progress = NULL;\n \tint local_error = 0;\n@@ -2906,13 +2886,13 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n \t\tif (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW))\n \t\t\ttotal += g->num_commits_in_base;\n \n-\t\tprogress = start_progress(r,\n+\t\tprogress = start_progress(g->odb_source->odb->repo,\n \t\t\t\t\t  _(\"Verifying commits in commit graph\"),\n \t\t\t\t\t  total);\n \t}\n \n \tfor (; g; g = g->base_graph) {\n-\t\tlocal_error |= verify_one_commit_graph(r, g, progress, &seen);\n+\t\tlocal_error |= verify_one_commit_graph(g, progress, &seen);\n \t\tif (flags & COMMIT_GRAPH_VERIFY_SHALLOW)\n \t\t\tbreak;\n \t}\ndiff --git a/commit-graph.h b/commit-graph.h\nindex a2471e9bdc..ad0bce5ed1 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -114,14 +114,12 @@ struct commit_graph {\n \tstruct bloom_filter_settings *bloom_filter_settings;\n };\n \n-struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n-\t\t\t\t\t\t int fd, struct stat *st,\n-\t\t\t\t\t\t struct odb_source *source);\n-struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n+struct commit_graph *load_commit_graph_one_fd_st(struct odb_source *source,\n+\t\t\t\t\t\t int fd, struct stat *st);\n+struct commit_graph *load_commit_graph_chain_fd_st(struct object_database *odb,\n \t\t\t\t\t\t   int fd, struct stat *st,\n \t\t\t\t\t\t   int *incomplete_chain);\n-struct commit_graph *read_commit_graph_one(struct repository *r,\n-\t\t\t\t\t   struct odb_source *source);\n+struct commit_graph *read_commit_graph_one(struct odb_source *source);\n \n struct repo_settings;\n \n@@ -185,7 +183,7 @@ int write_commit_graph(struct odb_source *source,\n \n #define COMMIT_GRAPH_VERIFY_SHALLOW\t(1 << 0)\n \n-int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags);\n+int verify_commit_graph(struct commit_graph *g, int flags);\n \n void close_commit_graph(struct object_database *);\n void free_commit_graph(struct commit_graph *);\ndiff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c\nindex ef5339bbee..6a5f64e473 100644\n--- a/t/helper/test-read-graph.c\n+++ b/t/helper/test-read-graph.c\n@@ -81,7 +81,7 @@ int cmd__read_graph(int argc, const char **argv)\n \n \tprepare_repo_settings(the_repository);\n \n-\tgraph = read_commit_graph_one(the_repository, source);\n+\tgraph = read_commit_graph_one(source);\n \tif (!graph) {\n \t\tret = 1;\n \t\tgoto done;\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523655","messageId":"aJNLxfL5ElFAzNz9@ugly","threadId":"63902","inReplyTo":"20250806-b4-pks-commit-graph-wo-the-repository-v2-3-911bae638e61@pks.im","subject":"Re: [PATCH v2 03/10] commit-graph: fix type for some write options","fromName":"Oswald Buddenhagen","fromEmail":"oswald.buddenhagen@gmx.de","sentAt":"2025-08-06T12:34:13Z","receivedAt":"2025-08-06T12:34:22Z","isPatch":true,"sender":{"key":"oswald.buddenhagen@gmx.de","avatar":"https://avatars.githubusercontent.com/u/812380?v=4"},"body":"On Wed, Aug 06, 2025 at 02:00:08PM +0200, Patrick Steinhardt wrote:\n>+\t\tOPT_UNSIGNED(0, \"max-commits\", &write_opts.max_commits,\n>\n>+\tsize_t max_commits;\n> \ndunno, this really seems to be crying for OPT_SIZE_T being split off.\n\n"},{"id":"523656","messageId":"aJNQm1r_FOIqsDlZ@ugly","threadId":"63902","inReplyTo":"aJL06Nlee6CR-KK0@pks.im","subject":"Re: [PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Oswald Buddenhagen","fromEmail":"oswald.buddenhagen@gmx.de","sentAt":"2025-08-06T12:54:51Z","receivedAt":"2025-08-06T12:54:53Z","isPatch":true,"sender":{"key":"oswald.buddenhagen@gmx.de","avatar":"https://avatars.githubusercontent.com/u/812380?v=4"},"body":"On Wed, Aug 06, 2025 at 08:23:36AM +0200, Patrick Steinhardt wrote:\n>On Mon, Aug 04, 2025 at 05:44:06PM -0400, Taylor Blau wrote:\n>> I wrote these counters in 312cff5207 (bloom: split \n>> 'get_bloom_filter()'\n>> in two, 2020-09-16) and 59f0d5073f (bloom: encode out-of-bounds filters\n>> as non-empty, 2020-09-17), and I don't see a compelling reason that\n>> these should be unsigned.\n>\n>I think that is going backwards though: the question to ask is why\n>should these be signed if they cannot ever be negative?\n>\n>> It's true that we don't have any need for negative values here since we\n>> are counting from zero, but I don't think that alone justifies changing\n>> the signed-ness here.\n>> \n>> Is there a reason beyond \"these are always non-negative\" that changing\n>> the signed-ness is warranted? If so, let's discuss that and make sure\n>> that it is documented in the commit message. If not, I think we could\n>> drop this patch (and optionally the patch before it as well).\n>\n>Yes, there is: it makes code easier to reason about for the reader, and\n>it means that we don't have to guard ourselves against negative values.\n>\n>If I see a counting variable that is signed I immediately jump to the\n>question of whether or not it can ever be a negative value. I assume\n>that the author of this code _intentfully_ made it signed to cater to a\n>specific edge case.\n>\nwell, there is also the diametrically opposed view:\nhttps://google.github.io/styleguide/cppguide.html#Integer_Types\nhttps://critical.eschertech.com/2010/04/07/danger-unsigned-types-used-here/\nhttps://soundsoftware.ac.uk/c-pitfall-unsigned\nhttps://stackoverflow.com/questions/30395205/why-are-unsigned-integers-error-prone\n..\n\nin isync, i standardized on unsigned where possible (e2d3b4d55), and \nsure enough, i introduced one of those underflow bugs not much later \n(859b7dd7f => 12e30ce56) ...\n"},{"id":"523662","messageId":"xmqqa54cwj9r.fsf@gitster.g","threadId":"63902","inReplyTo":"aJNLxfL5ElFAzNz9@ugly","subject":"Re: [PATCH v2 03/10] commit-graph: fix type for some write options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-08-06T15:40:32Z","receivedAt":"2025-08-06T15:40:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Oswald Buddenhagen <oswald.buddenhagen@gmx.de> writes:\n\n> On Wed, Aug 06, 2025 at 02:00:08PM +0200, Patrick Steinhardt wrote:\n>>+\t\tOPT_UNSIGNED(0, \"max-commits\", &write_opts.max_commits,\n>>\n>>+\tsize_t max_commits;\n>> \n> dunno, this really seems to be crying for OPT_SIZE_T being split off.\n\nOr just use \"unsigned int\".\n\nReally, what does NUMBER OF commits we will handle have anything to\ndo with how many bytes of core we ask to grab from the system?\n\nThis \"we count things in size_t\" is a superstition we should stop.\n\n"},{"id":"523663","messageId":"xmqq4iukwj83.fsf@gitster.g","threadId":"63902","inReplyTo":"aJL06Nlee6CR-KK0@pks.im","subject":"Re: [PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-08-06T15:41:32Z","receivedAt":"2025-08-06T15:41:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n>> I wrote these counters in 312cff5207 (bloom: split 'get_bloom_filter()'\n>> in two, 2020-09-16) and 59f0d5073f (bloom: encode out-of-bounds filters\n>> as non-empty, 2020-09-17), and I don't see a compelling reason that\n>> these should be unsigned.\n>\n> I think that is going backwards though: the question to ask is why\n> should these be signed if they cannot ever be negative?\n\nEarlier I gave an example of allowing for a \"not yet counted\"\nsentinel value for a variable or a structure member.  Another\nexample may be for a function that counts that also needs to signal\nan error, and as usual in any C programs, the natural way to do so\nfor any function whose \"normal\" return values are non-negative\nintegers is to signal errors with a negative value.\n\nNote that a structure member or a variable that does not need such a\n\"not yet counted\" sentinel value (e.g., it may have a separate\n\"counted already\" member associated with it, or the nature of the\nthing it counts does not have such \"not yet counted\" state), and it\nis possible for such a variable to live happily with a function that\ncan signal an error.\n\nIt means the variable that receives the counted result from such a\nfunction may be able to use only half a range of values as its type\nimplies, if that helper function is the only source of information\nthat is assigned to it, though.\n\nIf the counter in question never needs to store such a sentinel\nvalue itself, then I am OK for it to be unsigned, and that is\nexactly why I said \"not always a valid excuse\".  But if the counter\nvariable or structure member has to work with functions that need to\nreturn sentinel values (like platform natural int that can use the\nusual \"negative is an error, non-negative is a normal result\"), it\nmay have less chance to trigger the -Wsign-compare irritation, if\nyou made it also signed.\n"},{"id":"523670","messageId":"xmqqa54cuv8z.fsf@gitster.g","threadId":"63902","inReplyTo":"aJNQm1r_FOIqsDlZ@ugly","subject":"Re: [PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-08-06T19:04:44Z","receivedAt":"2025-08-06T19:04:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Oswald Buddenhagen <oswald.buddenhagen@gmx.de> writes:\n\n> On Wed, Aug 06, 2025 at 08:23:36AM +0200, Patrick Steinhardt wrote:\n>>If I see a counting variable that is signed I immediately jump to the\n>>question of whether or not it can ever be a negative value. I assume\n>>that the author of this code _intentfully_ made it signed to cater to a\n>>specific edge case.\n>>\n> well, there is also the diametrically opposed view:\n> https://google.github.io/styleguide/cppguide.html#Integer_Types\n> https://critical.eschertech.com/2010/04/07/danger-unsigned-types-used-here/\n> https://soundsoftware.ac.uk/c-pitfall-unsigned\n> https://stackoverflow.com/questions/30395205/why-are-unsigned-integers-error-prone\n> ..\n>\n> in isync, i standardized on unsigned where possible (e2d3b4d55), and\n> sure enough, i introduced one of those underflow bugs not much later\n> (859b7dd7f => 12e30ce56) ...\n\nThanks for an amusing reading list ;-)\n\n"},{"id":"523710","messageId":"aJRP_muuzCAy3mzF@pks.im","threadId":"63902","inReplyTo":"xmqq4iukwj83.fsf@gitster.g","subject":"Re: [PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-07T07:04:30Z","receivedAt":"2025-08-07T07:04:37Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Wed, Aug 06, 2025 at 08:41:32AM -0700, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> >> I wrote these counters in 312cff5207 (bloom: split 'get_bloom_filter()'\n> >> in two, 2020-09-16) and 59f0d5073f (bloom: encode out-of-bounds filters\n> >> as non-empty, 2020-09-17), and I don't see a compelling reason that\n> >> these should be unsigned.\n> >\n> > I think that is going backwards though: the question to ask is why\n> > should these be signed if they cannot ever be negative?\n> \n> Earlier I gave an example of allowing for a \"not yet counted\"\n> sentinel value for a variable or a structure member.  Another\n> example may be for a function that counts that also needs to signal\n> an error, and as usual in any C programs, the natural way to do so\n> for any function whose \"normal\" return values are non-negative\n> integers is to signal errors with a negative value.\n> \n> Note that a structure member or a variable that does not need such a\n> \"not yet counted\" sentinel value (e.g., it may have a separate\n> \"counted already\" member associated with it, or the nature of the\n> thing it counts does not have such \"not yet counted\" state), and it\n> is possible for such a variable to live happily with a function that\n> can signal an error.\n> \n> It means the variable that receives the counted result from such a\n> function may be able to use only half a range of values as its type\n> implies, if that helper function is the only source of information\n> that is assigned to it, though.\n> \n> If the counter in question never needs to store such a sentinel\n> value itself, then I am OK for it to be unsigned, and that is\n> exactly why I said \"not always a valid excuse\".  But if the counter\n> variable or structure member has to work with functions that need to\n> return sentinel values (like platform natural int that can use the\n> usual \"negative is an error, non-negative is a normal result\"), it\n> may have less chance to trigger the -Wsign-compare irritation, if\n> you made it also signed.\n\nYup, fully agreed, and this is a good reason why it should be signed. In\nthe case at hand though we never use such sentinel values, and I think\nmaking that explicit by using an unsigned type is a good thing as it\ntells the reader that \"Yup, no sentinels involved, it's a plain counter\nfrom 0 to $NUM_ENTRIES\".\n\nPatrick\n"},{"id":"523711","messageId":"aJRQuqzdoiQyYiHe@pks.im","threadId":"63902","inReplyTo":"xmqqa54cwj9r.fsf@gitster.g","subject":"Re: [PATCH v2 03/10] commit-graph: fix type for some write options","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-07T07:07:38Z","receivedAt":"2025-08-07T07:07:45Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Wed, Aug 06, 2025 at 08:40:32AM -0700, Junio C Hamano wrote:\n> Oswald Buddenhagen <oswald.buddenhagen@gmx.de> writes:\n> \n> > On Wed, Aug 06, 2025 at 02:00:08PM +0200, Patrick Steinhardt wrote:\n> >>+\t\tOPT_UNSIGNED(0, \"max-commits\", &write_opts.max_commits,\n> >>\n> >>+\tsize_t max_commits;\n> >> \n> > dunno, this really seems to be crying for OPT_SIZE_T being split off.\n> \n> Or just use \"unsigned int\".\n\nWe don't need `OPT_SIZE_T` because `OPT_UNSIGNED()` knows to handle\nunsigned integers of arbitrary widths. It does a `sizeof()` of the value\nand passes that as precision to the parsing code.\n\n> Really, what does NUMBER OF commits we will handle have anything to\n> do with how many bytes of core we ask to grab from the system?\n> \n> This \"we count things in size_t\" is a superstition we should stop.\n\nWill adapt to use `unsigned`.\n\nPatrick\n"},{"id":"523714","messageId":"20250807-b4-pks-commit-graph-wo-the-repository-v3-0-82edef830a1e@pks.im","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","subject":"[PATCH v3 00/10] commit-graph: remove reliance on global state","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-07T08:04:42Z","receivedAt":"2025-08-07T08:04:51Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Hi,\n\nthis patch series is another step on our long road towards not having\nglobal state. In addition to that, as commit-graphs are part of the\nobject database layer, this is also another step towards pluggable\nobject databases.\n\nChanges in v2:\n  - Use `unsigned` instead of `size_t` to count number of Bloom filters.\n  - Use `uint32_t` instead of `size_t` for number of commit graphs,\n    as this type is also used to iterate through this count already.\n  - Refactor `parse_commit_graph()` to take a repository instead of both\n    repo settings and a hash algo.\n  - Link to v1: https://lore.kernel.org/r/20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im\n\nChanges in v3:\n  - Use `unsigned` for commit-graph options instead of `size_t`.\n  - Link to v2: https://lore.kernel.org/r/20250806-b4-pks-commit-graph-wo-the-repository-v2-0-911bae638e61@pks.im\n\nThanks!\n\nPatrick\n\n---\nPatrick Steinhardt (10):\n      trace2: introduce function to trace unsigned integers\n      commit-graph: stop using signed integers to count Bloom filters\n      commit-graph: fix type for some write options\n      commit-graph: fix sign comparison warnings\n      commit-graph: stop using `the_hash_algo` via macros\n      commit-graph: store the hash algorithm instead of its length\n      commit-graph: refactor `parse_commit_graph()` to take a repository\n      commit-graph: stop using `the_hash_algo`\n      commit-graph: stop using `the_repository`\n      commit-graph: stop passing in redundant repository\n\n builtin/commit-graph.c       |  13 +-\n builtin/commit.c             |   2 +-\n builtin/merge.c              |   2 +-\n commit-graph.c               | 371 +++++++++++++++++++++----------------------\n commit-graph.h               |  25 ++-\n oss-fuzz/fuzz-commit-graph.c |   6 +-\n t/helper/test-read-graph.c   |   2 +-\n trace2.c                     |  14 ++\n trace2.h                     |   9 ++\n 9 files changed, 227 insertions(+), 217 deletions(-)\n\nRange-diff versus v2:\n\n 1:  16f0fd6fb4 =  1:  a652405a05 trace2: introduce function to trace unsigned integers\n 2:  53f12d827b =  2:  16a02e5dc0 commit-graph: stop using signed integers to count Bloom filters\n 3:  f8d920e132 !  3:  0cbd808dab commit-graph: fix type for some write options\n    @@ commit-graph.c: static void split_graph_merge_strategy(struct write_commit_graph\n     -\n     -\tint max_commits = 0;\n     -\tint size_mult = 2;\n    -+\tsize_t max_commits = 0;\n    -+\tsize_t size_mult = 2;\n    ++\tunsigned max_commits = 0;\n    ++\tunsigned size_mult = 2;\n      \n      \tif (ctx->opts) {\n      \t\tmax_commits = ctx->opts->max_commits;\n    @@ commit-graph.h: enum commit_graph_split_flags {\n      struct commit_graph_opts {\n     -\tint size_multiple;\n     -\tint max_commits;\n    -+\tsize_t size_multiple;\n    -+\tsize_t max_commits;\n    ++\tunsigned size_multiple;\n    ++\tunsigned max_commits;\n      \ttimestamp_t expire_time;\n      \tenum commit_graph_split_flags split_flags;\n      \tint max_new_filters;\n 4:  12d8d8f087 =  4:  8c1e6dc24c commit-graph: fix sign comparison warnings\n 5:  c7fc957de1 =  5:  9b0c61d221 commit-graph: stop using `the_hash_algo` via macros\n 6:  d41c5a419a =  6:  41e2e742ee commit-graph: store the hash algorithm instead of its length\n 7:  fec6cf25c7 =  7:  06dc3545fe commit-graph: refactor `parse_commit_graph()` to take a repository\n 8:  6a3ba128c2 =  8:  e06517c3a2 commit-graph: stop using `the_hash_algo`\n 9:  c2e549b474 =  9:  0f10e272bb commit-graph: stop using `the_repository`\n10:  59a325475d = 10:  e00dc6651c commit-graph: stop passing in redundant repository\n\n---\nbase-commit: e813a0200a7121b97fec535f0d0b460b0a33356c\nchange-id: 20250717-b4-pks-commit-graph-wo-the-repository-1dc2cacbc8e3\n\n"},{"id":"523715","messageId":"20250807-b4-pks-commit-graph-wo-the-repository-v3-1-82edef830a1e@pks.im","threadId":"63902","inReplyTo":"20250807-b4-pks-commit-graph-wo-the-repository-v3-0-82edef830a1e@pks.im","subject":"[PATCH v3 01/10] trace2: introduce function to trace unsigned integers","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-07T08:04:43Z","receivedAt":"2025-08-07T08:04:53Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"While we have `trace2_data_intmax()`, there is no equivalent function\nthat takes an unsigned integer. Introduce `trace2_data_uintmax()` to\nplug this gap.\n\nThis function will be used in a subsequent commit.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n trace2.c | 14 ++++++++++++++\n trace2.h |  9 +++++++++\n 2 files changed, 23 insertions(+)\n\ndiff --git a/trace2.c b/trace2.c\nindex c23c0a227b..a687944f7b 100644\n--- a/trace2.c\n+++ b/trace2.c\n@@ -948,6 +948,20 @@ void trace2_data_intmax_fl(const char *file, int line, const char *category,\n \tstrbuf_release(&buf_string);\n }\n \n+void trace2_data_uintmax_fl(const char *file, int line, const char *category,\n+\t\t\t    const struct repository *repo, const char *key,\n+\t\t\t    uintmax_t value)\n+{\n+\tstruct strbuf buf_string = STRBUF_INIT;\n+\n+\tif (!trace2_enabled)\n+\t\treturn;\n+\n+\tstrbuf_addf(&buf_string, \"%\" PRIuMAX, value);\n+\ttrace2_data_string_fl(file, line, category, repo, key, buf_string.buf);\n+\tstrbuf_release(&buf_string);\n+}\n+\n void trace2_data_json_fl(const char *file, int line, const char *category,\n \t\t\t const struct repository *repo, const char *key,\n \t\t\t const struct json_writer *value)\ndiff --git a/trace2.h b/trace2.h\nindex e4f23784e4..115c45a1eb 100644\n--- a/trace2.h\n+++ b/trace2.h\n@@ -463,6 +463,15 @@ void trace2_data_intmax_fl(const char *file, int line, const char *category,\n \ttrace2_data_intmax_fl(__FILE__, __LINE__, (category), (repo), (key), \\\n \t\t\t      (value))\n \n+void trace2_data_uintmax_fl(const char *file, int line, const char *category,\n+\t\t\t    const struct repository *repo, const char *key,\n+\t\t\t    uintmax_t value);\n+\n+#define trace2_data_uintmax(category, repo, key, value)                       \\\n+\ttrace2_data_uintmax_fl(__FILE__, __LINE__, (category), (repo), (key), \\\n+\t\t\t      (value))\n+\n+\n void trace2_data_json_fl(const char *file, int line, const char *category,\n \t\t\t const struct repository *repo, const char *key,\n \t\t\t const struct json_writer *jw);\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523716","messageId":"20250807-b4-pks-commit-graph-wo-the-repository-v3-2-82edef830a1e@pks.im","threadId":"63902","inReplyTo":"20250807-b4-pks-commit-graph-wo-the-repository-v3-0-82edef830a1e@pks.im","subject":"[PATCH v3 02/10] commit-graph: stop using signed integers to count Bloom filters","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-07T08:04:44Z","receivedAt":"2025-08-07T08:04:56Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"When writing a new commit graph we have a couple of counters that\nprovide statistics around what kind of Bloom filters we have or have not\nwritten. These counters naturally count from zero and are only ever\nincremented, but they use a signed integer as type regardless.\n\nRefactor those fields to be unsigned instead. Using an unsigned type\nmakes it explicit to the reader that they never have to worry about\nnegative values and thus makes the code easier to understand.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 30 +++++++++++++++---------------\n 1 file changed, 15 insertions(+), 15 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex bd7b6f5338..3fc1273ba5 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -1170,11 +1170,11 @@ struct write_commit_graph_context {\n \tsize_t total_bloom_filter_data_size;\n \tconst struct bloom_filter_settings *bloom_settings;\n \n-\tint count_bloom_filter_computed;\n-\tint count_bloom_filter_not_computed;\n-\tint count_bloom_filter_trunc_empty;\n-\tint count_bloom_filter_trunc_large;\n-\tint count_bloom_filter_upgraded;\n+\tunsigned count_bloom_filter_computed;\n+\tunsigned count_bloom_filter_not_computed;\n+\tunsigned count_bloom_filter_trunc_empty;\n+\tunsigned count_bloom_filter_trunc_large;\n+\tunsigned count_bloom_filter_upgraded;\n };\n \n static int write_graph_chunk_fanout(struct hashfile *f,\n@@ -1779,16 +1779,16 @@ void ensure_generations_valid(struct repository *r,\n \n static void trace2_bloom_filter_write_statistics(struct write_commit_graph_context *ctx)\n {\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-computed\",\n-\t\t\t   ctx->count_bloom_filter_computed);\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-not-computed\",\n-\t\t\t   ctx->count_bloom_filter_not_computed);\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-trunc-empty\",\n-\t\t\t   ctx->count_bloom_filter_trunc_empty);\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-trunc-large\",\n-\t\t\t   ctx->count_bloom_filter_trunc_large);\n-\ttrace2_data_intmax(\"commit-graph\", ctx->r, \"filter-upgraded\",\n-\t\t\t   ctx->count_bloom_filter_upgraded);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-computed\",\n+\t\t\t    ctx->count_bloom_filter_computed);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-not-computed\",\n+\t\t\t    ctx->count_bloom_filter_not_computed);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-trunc-empty\",\n+\t\t\t    ctx->count_bloom_filter_trunc_empty);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-trunc-large\",\n+\t\t\t    ctx->count_bloom_filter_trunc_large);\n+\ttrace2_data_uintmax(\"commit-graph\", ctx->r, \"filter-upgraded\",\n+\t\t\t    ctx->count_bloom_filter_upgraded);\n }\n \n static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523717","messageId":"20250807-b4-pks-commit-graph-wo-the-repository-v3-3-82edef830a1e@pks.im","threadId":"63902","inReplyTo":"20250807-b4-pks-commit-graph-wo-the-repository-v3-0-82edef830a1e@pks.im","subject":"[PATCH v3 03/10] commit-graph: fix type for some write options","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-07T08:04:45Z","receivedAt":"2025-08-07T08:04:59Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The options \"max-commits\" and \"size-multiple\" are both supposed to be\npositive integers and are documented as such, but we use a signed\ninteger field to store them. This causes sign comparison warnings in\n`split_graph_merge_strategy()` because we end up comparing the option\nvalues with the observed number of commits.\n\nFix the issue by converting the fields to be unsigned and convert the\noptions to use `OPT_UNSIGNED()` accordingly. This macro has only been\nintroduced recently, which might explain why the option values were\nsigned in the first place.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit-graph.c | 4 ++--\n commit-graph.c         | 5 ++---\n commit-graph.h         | 4 ++--\n 3 files changed, 6 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin/commit-graph.c b/builtin/commit-graph.c\nindex 25018a0b9d..145802afb7 100644\n--- a/builtin/commit-graph.c\n+++ b/builtin/commit-graph.c\n@@ -241,9 +241,9 @@ static int graph_write(int argc, const char **argv, const char *prefix,\n \t\t\tN_(\"allow writing an incremental commit-graph file\"),\n \t\t\tPARSE_OPT_OPTARG | PARSE_OPT_NONEG,\n \t\t\twrite_option_parse_split),\n-\t\tOPT_INTEGER(0, \"max-commits\", &write_opts.max_commits,\n+\t\tOPT_UNSIGNED(0, \"max-commits\", &write_opts.max_commits,\n \t\t\tN_(\"maximum number of commits in a non-base split commit-graph\")),\n-\t\tOPT_INTEGER(0, \"size-multiple\", &write_opts.size_multiple,\n+\t\tOPT_UNSIGNED(0, \"size-multiple\", &write_opts.size_multiple,\n \t\t\tN_(\"maximum ratio between two levels of a split commit-graph\")),\n \t\tOPT_EXPIRY_DATE(0, \"expire-time\", &write_opts.expire_time,\n \t\t\tN_(\"only expire files older than a given date-time\")),\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 3fc1273ba5..53bf83f7b5 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -2235,9 +2235,8 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)\n \tuint32_t num_commits;\n \tenum commit_graph_split_flags flags = COMMIT_GRAPH_SPLIT_UNSPECIFIED;\n \tuint32_t i;\n-\n-\tint max_commits = 0;\n-\tint size_mult = 2;\n+\tunsigned max_commits = 0;\n+\tunsigned size_mult = 2;\n \n \tif (ctx->opts) {\n \t\tmax_commits = ctx->opts->max_commits;\ndiff --git a/commit-graph.h b/commit-graph.h\nindex 78ab7b875b..f5b032e982 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -160,8 +160,8 @@ enum commit_graph_split_flags {\n };\n \n struct commit_graph_opts {\n-\tint size_multiple;\n-\tint max_commits;\n+\tunsigned size_multiple;\n+\tunsigned max_commits;\n \ttimestamp_t expire_time;\n \tenum commit_graph_split_flags split_flags;\n \tint max_new_filters;\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523718","messageId":"20250807-b4-pks-commit-graph-wo-the-repository-v3-4-82edef830a1e@pks.im","threadId":"63902","inReplyTo":"20250807-b4-pks-commit-graph-wo-the-repository-v3-0-82edef830a1e@pks.im","subject":"[PATCH v3 04/10] commit-graph: fix sign comparison warnings","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-07T08:04:46Z","receivedAt":"2025-08-07T08:05:03Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The \"commit-graph.c\" file has a bunch of sign comparison warnings:\n\n  - There are a bunch of variables that are declared as signed integers\n    even though they are used to count entities, like for example\n    `num_commit_graphs_before` and `num_commit_graphs_after`.\n\n  - There are several cases where we use signed loop variables to\n    iterate through an unsigned entity count.\n\n  - In `write_graph_chunk_base_1()` we count how many chunks we have\n    written in total. But while the value represents a positive\n    quantity, we still return a signed integer that we then later\n    compare with unsigned values.\n\n  - The Bloom settings hash version is being assigned `-1` even though\n    it's an unsigned value. This is used to indicate an unspecified\n    value and relies on 1's complement.\n\nFix all of these cases by either using the proper variable type or by\nadding casts as required.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 54 +++++++++++++++++++++++++++---------------------------\n 1 file changed, 27 insertions(+), 27 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 53bf83f7b5..7c0ded4532 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -1,5 +1,4 @@\n #define USE_THE_REPOSITORY_VARIABLE\n-#define DISABLE_SIGN_COMPARE_WARNINGS\n \n #include \"git-compat-util.h\"\n #include \"config.h\"\n@@ -569,7 +568,7 @@ static void validate_mixed_bloom_settings(struct commit_graph *g)\n static int add_graph_to_chain(struct commit_graph *g,\n \t\t\t      struct commit_graph *chain,\n \t\t\t      struct object_id *oids,\n-\t\t\t      int n)\n+\t\t\t      size_t n)\n {\n \tstruct commit_graph *cur_g = chain;\n \n@@ -622,7 +621,7 @@ int open_commit_graph_chain(const char *chain_file,\n \t\tclose(*fd);\n \t\treturn 0;\n \t}\n-\tif (st->st_size < the_hash_algo->hexsz) {\n+\tif (st->st_size < (ssize_t) the_hash_algo->hexsz) {\n \t\tclose(*fd);\n \t\tif (!st->st_size) {\n \t\t\t/* treat empty files the same as missing */\n@@ -643,15 +642,16 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \tstruct commit_graph *graph_chain = NULL;\n \tstruct strbuf line = STRBUF_INIT;\n \tstruct object_id *oids;\n-\tint i = 0, valid = 1, count;\n+\tint valid = 1;\n \tFILE *fp = xfdopen(fd, \"r\");\n+\tsize_t count;\n \n \tcount = st->st_size / (the_hash_algo->hexsz + 1);\n \tCALLOC_ARRAY(oids, count);\n \n \todb_prepare_alternates(r->objects);\n \n-\tfor (i = 0; i < count; i++) {\n+\tfor (size_t i = 0; i < count; i++) {\n \t\tstruct odb_source *source;\n \n \t\tif (strbuf_getline_lf(&line, fp) == EOF)\n@@ -1145,12 +1145,12 @@ struct write_commit_graph_context {\n \tint num_generation_data_overflows;\n \tunsigned long approx_nr_objects;\n \tstruct progress *progress;\n-\tint progress_done;\n+\tuint64_t progress_done;\n \tuint64_t progress_cnt;\n \n \tchar *base_graph_name;\n-\tint num_commit_graphs_before;\n-\tint num_commit_graphs_after;\n+\tuint32_t num_commit_graphs_before;\n+\tuint32_t num_commit_graphs_after;\n \tchar **commit_graph_filenames_before;\n \tchar **commit_graph_filenames_after;\n \tchar **commit_graph_hash_after;\n@@ -1181,7 +1181,7 @@ static int write_graph_chunk_fanout(struct hashfile *f,\n \t\t\t\t    void *data)\n {\n \tstruct write_commit_graph_context *ctx = data;\n-\tint i, count = 0;\n+\tsize_t i, count = 0;\n \tstruct commit **list = ctx->commits.list;\n \n \t/*\n@@ -1209,7 +1209,8 @@ static int write_graph_chunk_oids(struct hashfile *f,\n {\n \tstruct write_commit_graph_context *ctx = data;\n \tstruct commit **list = ctx->commits.list;\n-\tint count;\n+\tsize_t count;\n+\n \tfor (count = 0; count < ctx->commits.nr; count++, list++) {\n \t\tdisplay_progress(ctx->progress, ++ctx->progress_cnt);\n \t\thashwrite(f, (*list)->object.oid.hash, the_hash_algo->rawsz);\n@@ -1331,9 +1332,9 @@ static int write_graph_chunk_generation_data(struct hashfile *f,\n \t\t\t\t\t     void *data)\n {\n \tstruct write_commit_graph_context *ctx = data;\n-\tint i, num_generation_data_overflows = 0;\n+\tint num_generation_data_overflows = 0;\n \n-\tfor (i = 0; i < ctx->commits.nr; i++) {\n+\tfor (size_t i = 0; i < ctx->commits.nr; i++) {\n \t\tstruct commit *c = ctx->commits.list[i];\n \t\ttimestamp_t offset;\n \t\trepo_parse_commit(ctx->r, c);\n@@ -1355,8 +1356,8 @@ static int write_graph_chunk_generation_data_overflow(struct hashfile *f,\n \t\t\t\t\t\t      void *data)\n {\n \tstruct write_commit_graph_context *ctx = data;\n-\tint i;\n-\tfor (i = 0; i < ctx->commits.nr; i++) {\n+\n+\tfor (size_t i = 0; i < ctx->commits.nr; i++) {\n \t\tstruct commit *c = ctx->commits.list[i];\n \t\ttimestamp_t offset = commit_graph_data_at(c)->generation - c->date;\n \t\tdisplay_progress(ctx->progress, ++ctx->progress_cnt);\n@@ -1526,7 +1527,7 @@ static void add_missing_parents(struct write_commit_graph_context *ctx, struct c\n \n static void close_reachable(struct write_commit_graph_context *ctx)\n {\n-\tint i;\n+\tsize_t i;\n \tstruct commit *commit;\n \tenum commit_graph_split_flags flags = ctx->opts ?\n \t\tctx->opts->split_flags : COMMIT_GRAPH_SPLIT_UNSPECIFIED;\n@@ -1620,10 +1621,9 @@ static void compute_reachable_generation_numbers(\n \t\t\tstruct compute_generation_info *info,\n \t\t\tint generation_version)\n {\n-\tint i;\n \tstruct commit_list *list = NULL;\n \n-\tfor (i = 0; i < info->commits->nr; i++) {\n+\tfor (size_t i = 0; i < info->commits->nr; i++) {\n \t\tstruct commit *c = info->commits->list[i];\n \t\ttimestamp_t gen;\n \t\trepo_parse_commit(info->r, c);\n@@ -1714,7 +1714,7 @@ static void set_generation_v2(struct commit *c, timestamp_t t,\n \n static void compute_generation_numbers(struct write_commit_graph_context *ctx)\n {\n-\tint i;\n+\tsize_t i;\n \tstruct compute_generation_info info = {\n \t\t.r = ctx->r,\n \t\t.commits = &ctx->commits,\n@@ -1793,10 +1793,10 @@ static void trace2_bloom_filter_write_statistics(struct write_commit_graph_conte\n \n static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n {\n-\tint i;\n+\tsize_t i;\n \tstruct progress *progress = NULL;\n \tstruct commit **sorted_commits;\n-\tint max_new_filters;\n+\tsize_t max_new_filters;\n \n \tinit_bloom_filters();\n \n@@ -1814,7 +1814,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n \t\tQSORT(sorted_commits, ctx->commits.nr, commit_gen_cmp);\n \n \tmax_new_filters = ctx->opts && ctx->opts->max_new_filters >= 0 ?\n-\t\tctx->opts->max_new_filters : ctx->commits.nr;\n+\t\t(size_t) ctx->opts->max_new_filters : ctx->commits.nr;\n \n \tfor (i = 0; i < ctx->commits.nr; i++) {\n \t\tenum bloom_filter_computed computed = 0;\n@@ -2017,10 +2017,10 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx)\n \tstop_progress(&ctx->progress);\n }\n \n-static int write_graph_chunk_base_1(struct hashfile *f,\n-\t\t\t\t    struct commit_graph *g)\n+static size_t write_graph_chunk_base_1(struct hashfile *f,\n+\t\t\t\t       struct commit_graph *g)\n {\n-\tint num = 0;\n+\tsize_t num = 0;\n \n \tif (!g)\n \t\treturn 0;\n@@ -2034,7 +2034,7 @@ static int write_graph_chunk_base(struct hashfile *f,\n \t\t\t\t    void *data)\n {\n \tstruct write_commit_graph_context *ctx = data;\n-\tint num = write_graph_chunk_base_1(f, ctx->new_base_graph);\n+\tsize_t num = write_graph_chunk_base_1(f, ctx->new_base_graph);\n \n \tif (num != ctx->num_commit_graphs_after - 1) {\n \t\terror(_(\"failed to write correct number of base graph ids\"));\n@@ -2480,7 +2480,7 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)\n \t\tif (stat(path.buf, &st) < 0)\n \t\t\tcontinue;\n \n-\t\tif (st.st_mtime > expire_time)\n+\t\tif ((unsigned) st.st_mtime > expire_time)\n \t\t\tcontinue;\n \t\tif (path.len < 6 || strcmp(path.buf + path.len - 6, \".graph\"))\n \t\t\tcontinue;\n@@ -2576,7 +2576,7 @@ int write_commit_graph(struct odb_source *source,\n \t\t\tctx.changed_paths = 1;\n \n \t\t\t/* don't propagate the hash_version unless unspecified */\n-\t\t\tif (bloom_settings.hash_version == -1)\n+\t\t\tif (bloom_settings.hash_version == (unsigned) -1)\n \t\t\t\tbloom_settings.hash_version = g->bloom_filter_settings->hash_version;\n \t\t\tbloom_settings.bits_per_entry = g->bloom_filter_settings->bits_per_entry;\n \t\t\tbloom_settings.num_hashes = g->bloom_filter_settings->num_hashes;\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523719","messageId":"20250807-b4-pks-commit-graph-wo-the-repository-v3-5-82edef830a1e@pks.im","threadId":"63902","inReplyTo":"20250807-b4-pks-commit-graph-wo-the-repository-v3-0-82edef830a1e@pks.im","subject":"[PATCH v3 05/10] commit-graph: stop using `the_hash_algo` via macros","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-07T08:04:47Z","receivedAt":"2025-08-07T08:05:06Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have two macros `GRAPH_DATA_WIDTH` and `GRAPH_MIN_SIZE` that compute\nhash-dependent sizes. They do so by using the global `the_hash_algo`\nvariable though, which we want to get rid of over time.\n\nConvert these macros into functions that accept the hash algorithm as\ninput parameter. Adapt callers accordingly.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 25 ++++++++++++++++---------\n 1 file changed, 16 insertions(+), 9 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 7c0ded4532..e75fb8e6ea 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -52,8 +52,6 @@ void git_test_write_commit_graph_or_die(void)\n #define GRAPH_CHUNKID_BLOOMDATA 0x42444154 /* \"BDAT\" */\n #define GRAPH_CHUNKID_BASE 0x42415345 /* \"BASE\" */\n \n-#define GRAPH_DATA_WIDTH (the_hash_algo->rawsz + 16)\n-\n #define GRAPH_VERSION_1 0x1\n #define GRAPH_VERSION GRAPH_VERSION_1\n \n@@ -65,8 +63,6 @@ void git_test_write_commit_graph_or_die(void)\n \n #define GRAPH_HEADER_SIZE 8\n #define GRAPH_FANOUT_SIZE (4 * 256)\n-#define GRAPH_MIN_SIZE (GRAPH_HEADER_SIZE + 4 * CHUNK_TOC_ENTRY_SIZE \\\n-\t\t\t+ GRAPH_FANOUT_SIZE + the_hash_algo->rawsz)\n \n #define CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW (1ULL << 31)\n \n@@ -79,6 +75,16 @@ define_commit_slab(topo_level_slab, uint32_t);\n define_commit_slab(commit_pos, int);\n static struct commit_pos commit_pos = COMMIT_SLAB_INIT(1, commit_pos);\n \n+static size_t graph_data_width(const struct git_hash_algo *algop)\n+{\n+\treturn algop->rawsz + 16;\n+}\n+\n+static size_t graph_min_size(const struct git_hash_algo *algop)\n+{\n+\treturn GRAPH_HEADER_SIZE + 4 * CHUNK_TOC_ENTRY_SIZE + GRAPH_FANOUT_SIZE + algop->rawsz;\n+}\n+\n static void set_commit_pos(struct repository *r, const struct object_id *oid)\n {\n \tstatic int32_t max_pos;\n@@ -257,7 +263,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \n \tgraph_size = xsize_t(st->st_size);\n \n-\tif (graph_size < GRAPH_MIN_SIZE) {\n+\tif (graph_size < graph_min_size(the_hash_algo)) {\n \t\tclose(fd);\n \t\terror(_(\"commit-graph file is too small\"));\n \t\treturn NULL;\n@@ -313,7 +319,7 @@ static int graph_read_commit_data(const unsigned char *chunk_start,\n \t\t\t\t  size_t chunk_size, void *data)\n {\n \tstruct commit_graph *g = data;\n-\tif (chunk_size / GRAPH_DATA_WIDTH != g->num_commits)\n+\tif (chunk_size / graph_data_width(the_hash_algo) != g->num_commits)\n \t\treturn error(_(\"commit-graph commit data chunk is wrong size\"));\n \tg->chunk_commit_data = chunk_start;\n \treturn 0;\n@@ -378,7 +384,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \tif (!graph_map)\n \t\treturn NULL;\n \n-\tif (graph_size < GRAPH_MIN_SIZE)\n+\tif (graph_size < graph_min_size(the_hash_algo))\n \t\treturn NULL;\n \n \tdata = (const unsigned char *)graph_map;\n@@ -900,7 +906,7 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \t\tdie(_(\"invalid commit position. commit-graph is likely corrupt\"));\n \n \tlex_index = pos - g->num_commits_in_base;\n-\tcommit_data = g->chunk_commit_data + st_mult(GRAPH_DATA_WIDTH, lex_index);\n+\tcommit_data = g->chunk_commit_data + st_mult(graph_data_width(the_hash_algo), lex_index);\n \n \tgraph_data = commit_graph_data_at(item);\n \tgraph_data->graph_pos = pos;\n@@ -1104,7 +1110,8 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\tg = g->base_graph;\n \n \tcommit_data = g->chunk_commit_data +\n-\t\t\tst_mult(GRAPH_DATA_WIDTH, graph_pos - g->num_commits_in_base);\n+\t\t\tst_mult(graph_data_width(the_hash_algo),\n+\t\t\t\tgraph_pos - g->num_commits_in_base);\n \n \toidread(&oid, commit_data, the_repository->hash_algo);\n \tset_commit_tree(c, lookup_tree(r, &oid));\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523720","messageId":"20250807-b4-pks-commit-graph-wo-the-repository-v3-6-82edef830a1e@pks.im","threadId":"63902","inReplyTo":"20250807-b4-pks-commit-graph-wo-the-repository-v3-0-82edef830a1e@pks.im","subject":"[PATCH v3 06/10] commit-graph: store the hash algorithm instead of its length","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-07T08:04:48Z","receivedAt":"2025-08-07T08:05:09Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The commit-graph stores the length of the hash algorithm it uses. In\nsubsequent commits we'll need to pass the whole hash algorithm around\nthough, which we currently don't have access to.\n\nRefactor the code so that we store the hash algorithm instead of only\nits size.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 36 ++++++++++++++++++------------------\n commit-graph.h |  2 +-\n 2 files changed, 19 insertions(+), 19 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex e75fb8e6ea..430eab0b86 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -310,7 +310,7 @@ static int graph_read_oid_lookup(const unsigned char *chunk_start,\n {\n \tstruct commit_graph *g = data;\n \tg->chunk_oid_lookup = chunk_start;\n-\tif (chunk_size / g->hash_len != g->num_commits)\n+\tif (chunk_size / g->hash_algo->rawsz != g->num_commits)\n \t\treturn error(_(\"commit-graph OID lookup chunk is the wrong size\"));\n \treturn 0;\n }\n@@ -412,7 +412,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \n \tgraph = alloc_commit_graph();\n \n-\tgraph->hash_len = the_hash_algo->rawsz;\n+\tgraph->hash_algo = the_hash_algo;\n \tgraph->num_chunks = *(unsigned char*)(data + 6);\n \tgraph->data = graph_map;\n \tgraph->data_len = graph_size;\n@@ -477,7 +477,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t\tFREE_AND_NULL(graph->bloom_filter_settings);\n \t}\n \n-\toidread(&graph->oid, graph->data + graph->data_len - graph->hash_len,\n+\toidread(&graph->oid, graph->data + graph->data_len - graph->hash_algo->rawsz,\n \t\tthe_repository->hash_algo);\n \n \tfree_chunkfile(cf);\n@@ -583,7 +583,7 @@ static int add_graph_to_chain(struct commit_graph *g,\n \t\treturn 0;\n \t}\n \n-\tif (g->chunk_base_graphs_size / g->hash_len < n) {\n+\tif (g->chunk_base_graphs_size / g->hash_algo->rawsz < n) {\n \t\twarning(_(\"commit-graph base graphs chunk is too small\"));\n \t\treturn 0;\n \t}\n@@ -593,7 +593,7 @@ static int add_graph_to_chain(struct commit_graph *g,\n \n \t\tif (!cur_g ||\n \t\t    !oideq(&oids[n], &cur_g->oid) ||\n-\t\t    !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_len, n),\n+\t\t    !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_algo->rawsz, n),\n \t\t\t    the_repository->hash_algo)) {\n \t\t\twarning(_(\"commit-graph chain does not match\"));\n \t\t\treturn 0;\n@@ -805,7 +805,7 @@ int generation_numbers_enabled(struct repository *r)\n \t\treturn 0;\n \n \tfirst_generation = get_be32(g->chunk_commit_data +\n-\t\t\t\t    g->hash_len + 8) >> 2;\n+\t\t\t\t    g->hash_algo->rawsz + 8) >> 2;\n \n \treturn !!first_generation;\n }\n@@ -849,7 +849,7 @@ void close_commit_graph(struct object_database *o)\n static int bsearch_graph(struct commit_graph *g, const struct object_id *oid, uint32_t *pos)\n {\n \treturn bsearch_hash(oid->hash, g->chunk_oid_fanout,\n-\t\t\t    g->chunk_oid_lookup, g->hash_len, pos);\n+\t\t\t    g->chunk_oid_lookup, g->hash_algo->rawsz, pos);\n }\n \n static void load_oid_from_graph(struct commit_graph *g,\n@@ -869,7 +869,7 @@ static void load_oid_from_graph(struct commit_graph *g,\n \n \tlex_index = pos - g->num_commits_in_base;\n \n-\toidread(oid, g->chunk_oid_lookup + st_mult(g->hash_len, lex_index),\n+\toidread(oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, lex_index),\n \t\tthe_repository->hash_algo);\n }\n \n@@ -911,8 +911,8 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \tgraph_data = commit_graph_data_at(item);\n \tgraph_data->graph_pos = pos;\n \n-\tdate_high = get_be32(commit_data + g->hash_len + 8) & 0x3;\n-\tdate_low = get_be32(commit_data + g->hash_len + 12);\n+\tdate_high = get_be32(commit_data + g->hash_algo->rawsz + 8) & 0x3;\n+\tdate_low = get_be32(commit_data + g->hash_algo->rawsz + 12);\n \titem->date = (timestamp_t)((date_high << 32) | date_low);\n \n \tif (g->read_generation_data) {\n@@ -930,10 +930,10 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \t\t} else\n \t\t\tgraph_data->generation = item->date + offset;\n \t} else\n-\t\tgraph_data->generation = get_be32(commit_data + g->hash_len + 8) >> 2;\n+\t\tgraph_data->generation = get_be32(commit_data + g->hash_algo->rawsz + 8) >> 2;\n \n \tif (g->topo_levels)\n-\t\t*topo_level_slab_at(g->topo_levels, item) = get_be32(commit_data + g->hash_len + 8) >> 2;\n+\t\t*topo_level_slab_at(g->topo_levels, item) = get_be32(commit_data + g->hash_algo->rawsz + 8) >> 2;\n }\n \n static inline void set_commit_tree(struct commit *c, struct tree *t)\n@@ -957,7 +957,7 @@ static int fill_commit_in_graph(struct repository *r,\n \tfill_commit_graph_info(item, g, pos);\n \n \tlex_index = pos - g->num_commits_in_base;\n-\tcommit_data = g->chunk_commit_data + st_mult(g->hash_len + 16, lex_index);\n+\tcommit_data = g->chunk_commit_data + st_mult(g->hash_algo->rawsz + 16, lex_index);\n \n \titem->object.parsed = 1;\n \n@@ -965,12 +965,12 @@ static int fill_commit_in_graph(struct repository *r,\n \n \tpptr = &item->parents;\n \n-\tedge_value = get_be32(commit_data + g->hash_len);\n+\tedge_value = get_be32(commit_data + g->hash_algo->rawsz);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n \tpptr = insert_parent_or_die(r, g, edge_value, pptr);\n \n-\tedge_value = get_be32(commit_data + g->hash_len + 4);\n+\tedge_value = get_be32(commit_data + g->hash_algo->rawsz + 4);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n \tif (!(edge_value & GRAPH_EXTRA_EDGES_NEEDED)) {\n@@ -2622,7 +2622,7 @@ int write_commit_graph(struct odb_source *source,\n \t\tstruct commit_graph *g = ctx.r->objects->commit_graph;\n \t\tfor (i = 0; i < g->num_commits; i++) {\n \t\t\tstruct object_id oid;\n-\t\t\toidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),\n+\t\t\toidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n \t\t\t\tthe_repository->hash_algo);\n \t\t\toid_array_append(&ctx.oids, &oid);\n \t\t}\n@@ -2753,7 +2753,7 @@ static int verify_one_commit_graph(struct repository *r,\n \tfor (i = 0; i < g->num_commits; i++) {\n \t\tstruct commit *graph_commit;\n \n-\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),\n+\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n \t\t\tthe_repository->hash_algo);\n \n \t\tif (i && oidcmp(&prev_oid, &cur_oid) >= 0)\n@@ -2798,7 +2798,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\ttimestamp_t generation;\n \n \t\tdisplay_progress(progress, ++(*seen));\n-\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),\n+\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n \t\t\tthe_repository->hash_algo);\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\ndiff --git a/commit-graph.h b/commit-graph.h\nindex f5b032e982..2228c714cb 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -84,7 +84,7 @@ struct commit_graph {\n \tconst unsigned char *data;\n \tsize_t data_len;\n \n-\tunsigned char hash_len;\n+\tconst struct git_hash_algo *hash_algo;\n \tunsigned char num_chunks;\n \tuint32_t num_commits;\n \tstruct object_id oid;\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523721","messageId":"20250807-b4-pks-commit-graph-wo-the-repository-v3-7-82edef830a1e@pks.im","threadId":"63902","inReplyTo":"20250807-b4-pks-commit-graph-wo-the-repository-v3-0-82edef830a1e@pks.im","subject":"[PATCH v3 07/10] commit-graph: refactor `parse_commit_graph()` to take a repository","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-07T08:04:49Z","receivedAt":"2025-08-07T08:05:12Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Refactor `parse_commit_graph()` so that it takes a repository instead of\ntaking repository settings. On the one hand this allows us to get rid of\ninstances where we access `the_hash_algo` by using the repository's hash\nalgorithm instead. On the other hand it also allows us to move the call\nof `prepare_repo_settings()` into the function itself.\n\nNote that there's one small catch, as the commit-graph fuzzer calls this\nfunction directly without having a fully functional repository at hand.\nAnd while the fuzzer already initializes `the_repository` with relevant\ninfo, the call to `prepare_repo_settings()` would fail because we don't\nhave a fully-initialized repository.\n\nWork around the issue by also settings `settings.initialized` to pretend\nthat we've already read the settings.\n\nWhile at it, remove the redundant `parse_commit_graph()` declaration in\nthe fuzzer. It was added together with aa658574bf (commit-graph, fuzz:\nadd fuzzer for commit-graph, 2019-01-15), but as we also declared the\nsame function in \"commit-graph.h\" it wasn't ever needed.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c               | 23 ++++++++++++-----------\n commit-graph.h               |  2 +-\n oss-fuzz/fuzz-commit-graph.c |  6 ++----\n 3 files changed, 15 insertions(+), 16 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 430eab0b869..77b785a5e05 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -270,9 +270,8 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \t}\n \tgraph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);\n \tclose(fd);\n-\tprepare_repo_settings(r);\n-\tret = parse_commit_graph(&r->settings, graph_map, graph_size);\n \n+\tret = parse_commit_graph(r, graph_map, graph_size);\n \tif (ret)\n \t\tret->odb_source = source;\n \telse\n@@ -372,7 +371,7 @@ static int graph_read_bloom_data(const unsigned char *chunk_start,\n \treturn 0;\n }\n \n-struct commit_graph *parse_commit_graph(struct repo_settings *s,\n+struct commit_graph *parse_commit_graph(struct repository *r,\n \t\t\t\t\tvoid *graph_map, size_t graph_size)\n {\n \tconst unsigned char *data;\n@@ -384,7 +383,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \tif (!graph_map)\n \t\treturn NULL;\n \n-\tif (graph_size < graph_min_size(the_hash_algo))\n+\tif (graph_size < graph_min_size(r->hash_algo))\n \t\treturn NULL;\n \n \tdata = (const unsigned char *)graph_map;\n@@ -404,22 +403,22 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t}\n \n \thash_version = *(unsigned char*)(data + 5);\n-\tif (hash_version != oid_version(the_hash_algo)) {\n+\tif (hash_version != oid_version(r->hash_algo)) {\n \t\terror(_(\"commit-graph hash version %X does not match version %X\"),\n-\t\t      hash_version, oid_version(the_hash_algo));\n+\t\t      hash_version, oid_version(r->hash_algo));\n \t\treturn NULL;\n \t}\n \n \tgraph = alloc_commit_graph();\n \n-\tgraph->hash_algo = the_hash_algo;\n+\tgraph->hash_algo = r->hash_algo;\n \tgraph->num_chunks = *(unsigned char*)(data + 6);\n \tgraph->data = graph_map;\n \tgraph->data_len = graph_size;\n \n \tif (graph_size < GRAPH_HEADER_SIZE +\n \t\t\t (graph->num_chunks + 1) * CHUNK_TOC_ENTRY_SIZE +\n-\t\t\t GRAPH_FANOUT_SIZE + the_hash_algo->rawsz) {\n+\t\t\t GRAPH_FANOUT_SIZE + r->hash_algo->rawsz) {\n \t\terror(_(\"commit-graph file is too small to hold %u chunks\"),\n \t\t      graph->num_chunks);\n \t\tfree(graph);\n@@ -450,7 +449,9 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \tpair_chunk(cf, GRAPH_CHUNKID_BASE, &graph->chunk_base_graphs,\n \t\t   &graph->chunk_base_graphs_size);\n \n-\tif (s->commit_graph_generation_version >= 2) {\n+\tprepare_repo_settings(r);\n+\n+\tif (r->settings.commit_graph_generation_version >= 2) {\n \t\tread_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,\n \t\t\t   graph_read_generation_data, graph);\n \t\tpair_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW,\n@@ -461,7 +462,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t\t\tgraph->read_generation_data = 1;\n \t}\n \n-\tif (s->commit_graph_changed_paths_version) {\n+\tif (r->settings.commit_graph_changed_paths_version) {\n \t\tread_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES,\n \t\t\t   graph_read_bloom_index, graph);\n \t\tread_chunk(cf, GRAPH_CHUNKID_BLOOMDATA,\n@@ -478,7 +479,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t}\n \n \toidread(&graph->oid, graph->data + graph->data_len - graph->hash_algo->rawsz,\n-\t\tthe_repository->hash_algo);\n+\t\tr->hash_algo);\n \n \tfree_chunkfile(cf);\n \treturn graph;\ndiff --git a/commit-graph.h b/commit-graph.h\nindex 2228c714cb1..4879643db0f 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -128,7 +128,7 @@ struct repo_settings;\n  * Callers should initialize the repo_settings with prepare_repo_settings()\n  * prior to calling parse_commit_graph().\n  */\n-struct commit_graph *parse_commit_graph(struct repo_settings *s,\n+struct commit_graph *parse_commit_graph(struct repository *r,\n \t\t\t\t\tvoid *graph_map, size_t graph_size);\n \n /*\ndiff --git a/oss-fuzz/fuzz-commit-graph.c b/oss-fuzz/fuzz-commit-graph.c\nindex fbb77fec197..fb8b8787a46 100644\n--- a/oss-fuzz/fuzz-commit-graph.c\n+++ b/oss-fuzz/fuzz-commit-graph.c\n@@ -4,9 +4,6 @@\n #include \"commit-graph.h\"\n #include \"repository.h\"\n \n-struct commit_graph *parse_commit_graph(struct repo_settings *s,\n-\t\t\t\t\tvoid *graph_map, size_t graph_size);\n-\n int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n \n int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n@@ -22,9 +19,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n \t * possible.\n \t */\n \trepo_set_hash_algo(the_repository, GIT_HASH_SHA1);\n+\tthe_repository->settings.initialized = 1;\n \tthe_repository->settings.commit_graph_generation_version = 2;\n \tthe_repository->settings.commit_graph_changed_paths_version = 1;\n-\tg = parse_commit_graph(&the_repository->settings, (void *)data, size);\n+\tg = parse_commit_graph(the_repository, (void *)data, size);\n \trepo_clear(the_repository);\n \tfree_commit_graph(g);\n \n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523722","messageId":"20250807-b4-pks-commit-graph-wo-the-repository-v3-8-82edef830a1e@pks.im","threadId":"63902","inReplyTo":"20250807-b4-pks-commit-graph-wo-the-repository-v3-0-82edef830a1e@pks.im","subject":"[PATCH v3 08/10] commit-graph: stop using `the_hash_algo`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-07T08:04:50Z","receivedAt":"2025-08-07T08:05:16Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Stop using `the_hash_algo` as it implicitly relies on `the_repository`.\nInstead, we either use the hash algo provided via the context or, if\nthere is no such hash algo, we use `the_repository` explicitly. Such\nuses will be removed in subsequent commits.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit-graph.c |  3 ++-\n commit-graph.c         | 27 ++++++++++++++-------------\n commit-graph.h         |  3 ++-\n 3 files changed, 18 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/commit-graph.c b/builtin/commit-graph.c\nindex 145802afb7..680b03a83a 100644\n--- a/builtin/commit-graph.c\n+++ b/builtin/commit-graph.c\n@@ -108,7 +108,8 @@ static int graph_verify(int argc, const char **argv, const char *prefix,\n \t\topened = OPENED_GRAPH;\n \telse if (errno != ENOENT)\n \t\tdie_errno(_(\"Could not open commit-graph '%s'\"), graph_name);\n-\telse if (open_commit_graph_chain(chain_name, &fd, &st))\n+\telse if (open_commit_graph_chain(chain_name, &fd, &st,\n+\t\t\t\t\t the_repository->hash_algo))\n \t\topened = OPENED_CHAIN;\n \telse if (errno != ENOENT)\n \t\tdie_errno(_(\"could not open commit-graph chain '%s'\"), chain_name);\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 77b785a5e0..594eca4110 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -263,7 +263,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \n \tgraph_size = xsize_t(st->st_size);\n \n-\tif (graph_size < graph_min_size(the_hash_algo)) {\n+\tif (graph_size < graph_min_size(r->hash_algo)) {\n \t\tclose(fd);\n \t\terror(_(\"commit-graph file is too small\"));\n \t\treturn NULL;\n@@ -318,7 +318,7 @@ static int graph_read_commit_data(const unsigned char *chunk_start,\n \t\t\t\t  size_t chunk_size, void *data)\n {\n \tstruct commit_graph *g = data;\n-\tif (chunk_size / graph_data_width(the_hash_algo) != g->num_commits)\n+\tif (chunk_size / graph_data_width(g->hash_algo) != g->num_commits)\n \t\treturn error(_(\"commit-graph commit data chunk is wrong size\"));\n \tg->chunk_commit_data = chunk_start;\n \treturn 0;\n@@ -619,7 +619,8 @@ static int add_graph_to_chain(struct commit_graph *g,\n }\n \n int open_commit_graph_chain(const char *chain_file,\n-\t\t\t    int *fd, struct stat *st)\n+\t\t\t    int *fd, struct stat *st,\n+\t\t\t    const struct git_hash_algo *hash_algo)\n {\n \t*fd = git_open(chain_file);\n \tif (*fd < 0)\n@@ -628,7 +629,7 @@ int open_commit_graph_chain(const char *chain_file,\n \t\tclose(*fd);\n \t\treturn 0;\n \t}\n-\tif (st->st_size < (ssize_t) the_hash_algo->hexsz) {\n+\tif (st->st_size < (ssize_t) hash_algo->hexsz) {\n \t\tclose(*fd);\n \t\tif (!st->st_size) {\n \t\t\t/* treat empty files the same as missing */\n@@ -653,7 +654,7 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \tFILE *fp = xfdopen(fd, \"r\");\n \tsize_t count;\n \n-\tcount = st->st_size / (the_hash_algo->hexsz + 1);\n+\tcount = st->st_size / (r->hash_algo->hexsz + 1);\n \tCALLOC_ARRAY(oids, count);\n \n \todb_prepare_alternates(r->objects);\n@@ -715,7 +716,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,\n \tint fd;\n \tstruct commit_graph *g = NULL;\n \n-\tif (open_commit_graph_chain(chain_file, &fd, &st)) {\n+\tif (open_commit_graph_chain(chain_file, &fd, &st, r->hash_algo)) {\n \t\tint incomplete;\n \t\t/* ownership of fd is taken over by load function */\n \t\tg = load_commit_graph_chain_fd_st(r, fd, &st, &incomplete);\n@@ -907,7 +908,7 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \t\tdie(_(\"invalid commit position. commit-graph is likely corrupt\"));\n \n \tlex_index = pos - g->num_commits_in_base;\n-\tcommit_data = g->chunk_commit_data + st_mult(graph_data_width(the_hash_algo), lex_index);\n+\tcommit_data = g->chunk_commit_data + st_mult(graph_data_width(g->hash_algo), lex_index);\n \n \tgraph_data = commit_graph_data_at(item);\n \tgraph_data->graph_pos = pos;\n@@ -1111,7 +1112,7 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\tg = g->base_graph;\n \n \tcommit_data = g->chunk_commit_data +\n-\t\t\tst_mult(graph_data_width(the_hash_algo),\n+\t\t\tst_mult(graph_data_width(g->hash_algo),\n \t\t\t\tgraph_pos - g->num_commits_in_base);\n \n \toidread(&oid, commit_data, the_repository->hash_algo);\n@@ -1221,7 +1222,7 @@ static int write_graph_chunk_oids(struct hashfile *f,\n \n \tfor (count = 0; count < ctx->commits.nr; count++, list++) {\n \t\tdisplay_progress(ctx->progress, ++ctx->progress_cnt);\n-\t\thashwrite(f, (*list)->object.oid.hash, the_hash_algo->rawsz);\n+\t\thashwrite(f, (*list)->object.oid.hash, f->algop->rawsz);\n \t}\n \n \treturn 0;\n@@ -1252,7 +1253,7 @@ static int write_graph_chunk_data(struct hashfile *f,\n \t\t\tdie(_(\"unable to parse commit %s\"),\n \t\t\t\toid_to_hex(&(*list)->object.oid));\n \t\ttree = get_commit_tree_oid(*list);\n-\t\thashwrite(f, tree->hash, the_hash_algo->rawsz);\n+\t\thashwrite(f, tree->hash, ctx->r->hash_algo->rawsz);\n \n \t\tparent = (*list)->parents;\n \n@@ -2034,7 +2035,7 @@ static size_t write_graph_chunk_base_1(struct hashfile *f,\n \t\treturn 0;\n \n \tnum = write_graph_chunk_base_1(f, g->base_graph);\n-\thashwrite(f, g->oid.hash, the_hash_algo->rawsz);\n+\thashwrite(f, g->oid.hash, g->hash_algo->rawsz);\n \treturn num + 1;\n }\n \n@@ -2058,7 +2059,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \tstruct hashfile *f;\n \tstruct tempfile *graph_layer; /* when ctx->split is non-zero */\n \tstruct lock_file lk = LOCK_INIT;\n-\tconst unsigned hashsz = the_hash_algo->rawsz;\n+\tconst unsigned hashsz = ctx->r->hash_algo->rawsz;\n \tstruct strbuf progress_title = STRBUF_INIT;\n \tstruct chunkfile *cf;\n \tunsigned char file_hash[GIT_MAX_RAWSZ];\n@@ -2146,7 +2147,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \thashwrite_be32(f, GRAPH_SIGNATURE);\n \n \thashwrite_u8(f, GRAPH_VERSION);\n-\thashwrite_u8(f, oid_version(the_hash_algo));\n+\thashwrite_u8(f, oid_version(ctx->r->hash_algo));\n \thashwrite_u8(f, get_num_chunks(cf));\n \thashwrite_u8(f, ctx->num_commit_graphs_after - 1);\n \ndiff --git a/commit-graph.h b/commit-graph.h\nindex 4879643db0..5f417f7666 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -32,7 +32,8 @@ struct string_list;\n char *get_commit_graph_filename(struct odb_source *source);\n char *get_commit_graph_chain_filename(struct odb_source *source);\n int open_commit_graph(const char *graph_file, int *fd, struct stat *st);\n-int open_commit_graph_chain(const char *chain_file, int *fd, struct stat *st);\n+int open_commit_graph_chain(const char *chain_file, int *fd, struct stat *st,\n+\t\t\t    const struct git_hash_algo *hash_algo);\n \n /*\n  * Given a commit struct, try to fill the commit struct info, including:\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523723","messageId":"20250807-b4-pks-commit-graph-wo-the-repository-v3-9-82edef830a1e@pks.im","threadId":"63902","inReplyTo":"20250807-b4-pks-commit-graph-wo-the-repository-v3-0-82edef830a1e@pks.im","subject":"[PATCH v3 09/10] commit-graph: stop using `the_repository`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-07T08:04:51Z","receivedAt":"2025-08-07T08:05:19Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"There's still a bunch of uses of `the_repository` in \"commit-graph.c\",\nwhich we want to stop using due to it being a global variable. Refactor\nthe code to stop using `the_repository` in favor of the repository\nprovided via the calling context.\n\nThis allows us to drop the `USE_THE_REPOSITORY_VARIABLE` macro.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit.c |  2 +-\n builtin/merge.c  |  2 +-\n commit-graph.c   | 77 ++++++++++++++++++++++++++++----------------------------\n commit-graph.h   |  2 +-\n 4 files changed, 42 insertions(+), 41 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 63e7158e98..8ca0aede48 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1933,7 +1933,7 @@ int cmd_commit(int argc,\n \t\t      \"new index file. Check that disk is not full and quota is\\n\"\n \t\t      \"not exceeded, and then \\\"git restore --staged :/\\\" to recover.\"));\n \n-\tgit_test_write_commit_graph_or_die();\n+\tgit_test_write_commit_graph_or_die(the_repository->objects->sources);\n \n \trepo_rerere(the_repository, 0);\n \trun_auto_maintenance(quiet);\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 18b22c0a26..263cb58471 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1862,7 +1862,7 @@ int cmd_merge(int argc,\n \tif (squash) {\n \t\tfinish(head_commit, remoteheads, NULL, NULL);\n \n-\t\tgit_test_write_commit_graph_or_die();\n+\t\tgit_test_write_commit_graph_or_die(the_repository->objects->sources);\n \t} else\n \t\twrite_merge_state(remoteheads);\n \ndiff --git a/commit-graph.c b/commit-graph.c\nindex 594eca4110..8e087fc4e6 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -1,5 +1,3 @@\n-#define USE_THE_REPOSITORY_VARIABLE\n-\n #include \"git-compat-util.h\"\n #include \"config.h\"\n #include \"csum-file.h\"\n@@ -27,7 +25,7 @@\n #include \"tree.h\"\n #include \"chunk-format.h\"\n \n-void git_test_write_commit_graph_or_die(void)\n+void git_test_write_commit_graph_or_die(struct odb_source *source)\n {\n \tint flags = 0;\n \tif (!git_env_bool(GIT_TEST_COMMIT_GRAPH, 0))\n@@ -36,8 +34,7 @@ void git_test_write_commit_graph_or_die(void)\n \tif (git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0))\n \t\tflags = COMMIT_GRAPH_WRITE_BLOOM_FILTERS;\n \n-\tif (write_commit_graph_reachable(the_repository->objects->sources,\n-\t\t\t\t\t flags, NULL))\n+\tif (write_commit_graph_reachable(source, flags, NULL))\n \t\tdie(\"failed to write commit-graph under GIT_TEST_COMMIT_GRAPH\");\n }\n \n@@ -595,7 +592,7 @@ static int add_graph_to_chain(struct commit_graph *g,\n \t\tif (!cur_g ||\n \t\t    !oideq(&oids[n], &cur_g->oid) ||\n \t\t    !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_algo->rawsz, n),\n-\t\t\t    the_repository->hash_algo)) {\n+\t\t\t    g->hash_algo)) {\n \t\t\twarning(_(\"commit-graph chain does not match\"));\n \t\t\treturn 0;\n \t\t}\n@@ -665,7 +662,7 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \t\tif (strbuf_getline_lf(&line, fp) == EOF)\n \t\t\tbreak;\n \n-\t\tif (get_oid_hex(line.buf, &oids[i])) {\n+\t\tif (get_oid_hex_algop(line.buf, &oids[i], r->hash_algo)) {\n \t\t\twarning(_(\"invalid commit-graph chain: line '%s' not a hash\"),\n \t\t\t\tline.buf);\n \t\t\tvalid = 0;\n@@ -751,7 +748,7 @@ static void prepare_commit_graph_one(struct repository *r,\n  * Return 1 if commit_graph is non-NULL, and 0 otherwise.\n  *\n  * On the first invocation, this function attempts to load the commit\n- * graph if the_repository is configured to have one.\n+ * graph if the repository is configured to have one.\n  */\n static int prepare_commit_graph(struct repository *r)\n {\n@@ -872,7 +869,7 @@ static void load_oid_from_graph(struct commit_graph *g,\n \tlex_index = pos - g->num_commits_in_base;\n \n \toidread(oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, lex_index),\n-\t\tthe_repository->hash_algo);\n+\t\tg->hash_algo);\n }\n \n static struct commit_list **insert_parent_or_die(struct repository *r,\n@@ -1115,7 +1112,7 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\t\tst_mult(graph_data_width(g->hash_algo),\n \t\t\t\tgraph_pos - g->num_commits_in_base);\n \n-\toidread(&oid, commit_data, the_repository->hash_algo);\n+\toidread(&oid, commit_data, g->hash_algo);\n \tset_commit_tree(c, lookup_tree(r, &oid));\n \n \treturn c->maybe_tree;\n@@ -1543,7 +1540,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Loading known commits in commit graph\"),\n \t\t\t\t\tctx->oids.nr);\n \tfor (i = 0; i < ctx->oids.nr; i++) {\n@@ -1561,7 +1558,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)\n \t */\n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Expanding reachable commits in commit graph\"),\n \t\t\t\t\t0);\n \tfor (i = 0; i < ctx->oids.nr; i++) {\n@@ -1582,7 +1579,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Clearing commit marks in commit graph\"),\n \t\t\t\t\tctx->oids.nr);\n \tfor (i = 0; i < ctx->oids.nr; i++) {\n@@ -1699,7 +1696,7 @@ static void compute_topological_levels(struct write_commit_graph_context *ctx)\n \tif (ctx->report_progress)\n \t\tinfo.progress = ctx->progress\n \t\t\t      = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Computing commit graph topological levels\"),\n \t\t\t\t\tctx->commits.nr);\n \n@@ -1734,7 +1731,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)\n \tif (ctx->report_progress)\n \t\tinfo.progress = ctx->progress\n \t\t\t      = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Computing commit graph generation numbers\"),\n \t\t\t\t\tctx->commits.nr);\n \n@@ -1811,7 +1808,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tprogress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\t_(\"Computing commit changed paths Bloom filters\"),\n \t\t\tctx->commits.nr);\n \n@@ -1857,6 +1854,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n }\n \n struct refs_cb_data {\n+\tstruct repository *repo;\n \tstruct oidset *commits;\n \tstruct progress *progress;\n };\n@@ -1869,9 +1867,9 @@ static int add_ref_to_set(const char *refname UNUSED,\n \tstruct object_id peeled;\n \tstruct refs_cb_data *data = (struct refs_cb_data *)cb_data;\n \n-\tif (!peel_iterated_oid(the_repository, oid, &peeled))\n+\tif (!peel_iterated_oid(data->repo, oid, &peeled))\n \t\toid = &peeled;\n-\tif (odb_read_object_info(the_repository->objects, oid, NULL) == OBJ_COMMIT)\n+\tif (odb_read_object_info(data->repo->objects, oid, NULL) == OBJ_COMMIT)\n \t\toidset_insert(data->commits, oid);\n \n \tdisplay_progress(data->progress, oidset_size(data->commits));\n@@ -1888,13 +1886,15 @@ int write_commit_graph_reachable(struct odb_source *source,\n \tint result;\n \n \tmemset(&data, 0, sizeof(data));\n+\tdata.repo = source->odb->repo;\n \tdata.commits = &commits;\n+\n \tif (flags & COMMIT_GRAPH_WRITE_PROGRESS)\n \t\tdata.progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tsource->odb->repo,\n \t\t\t_(\"Collecting referenced commits\"), 0);\n \n-\trefs_for_each_ref(get_main_ref_store(the_repository), add_ref_to_set,\n+\trefs_for_each_ref(get_main_ref_store(source->odb->repo), add_ref_to_set,\n \t\t\t  &data);\n \n \tstop_progress(&data.progress);\n@@ -1923,7 +1923,7 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx,\n \t\t\t       \"Finding commits for commit graph in %\"PRIuMAX\" packs\",\n \t\t\t       pack_indexes->nr),\n \t\t\t    (uintmax_t)pack_indexes->nr);\n-\t\tctx->progress = start_delayed_progress(the_repository,\n+\t\tctx->progress = start_delayed_progress(ctx->r,\n \t\t\t\t\t\t       progress_title.buf, 0);\n \t\tctx->progress_done = 0;\n \t}\n@@ -1977,7 +1977,7 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)\n {\n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\t_(\"Finding commits for commit graph among packed objects\"),\n \t\t\tctx->approx_nr_objects);\n \tfor_each_packed_object(ctx->r, add_packed_commits, ctx,\n@@ -1996,7 +1996,7 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx)\n \tctx->num_extra_edges = 0;\n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\t_(\"Finding extra edges in commit graph\"),\n \t\t\tctx->oids.nr);\n \toid_array_sort(&ctx->oids);\n@@ -2075,7 +2075,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\tctx->graph_name = get_commit_graph_filename(ctx->odb_source);\n \t}\n \n-\tif (safe_create_leading_directories(the_repository, ctx->graph_name)) {\n+\tif (safe_create_leading_directories(ctx->r, ctx->graph_name)) {\n \t\terror(_(\"unable to create leading directories of %s\"),\n \t\t\tctx->graph_name);\n \t\treturn -1;\n@@ -2094,18 +2094,18 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\t\treturn -1;\n \t\t}\n \n-\t\tif (adjust_shared_perm(the_repository, get_tempfile_path(graph_layer))) {\n+\t\tif (adjust_shared_perm(ctx->r, get_tempfile_path(graph_layer))) {\n \t\t\terror(_(\"unable to adjust shared permissions for '%s'\"),\n \t\t\t      get_tempfile_path(graph_layer));\n \t\t\treturn -1;\n \t\t}\n \n-\t\tf = hashfd(the_repository->hash_algo,\n+\t\tf = hashfd(ctx->r->hash_algo,\n \t\t\t   get_tempfile_fd(graph_layer), get_tempfile_path(graph_layer));\n \t} else {\n \t\thold_lock_file_for_update_mode(&lk, ctx->graph_name,\n \t\t\t\t\t       LOCK_DIE_ON_ERROR, 0444);\n-\t\tf = hashfd(the_repository->hash_algo,\n+\t\tf = hashfd(ctx->r->hash_algo,\n \t\t\t   get_lock_file_fd(&lk), get_lock_file_path(&lk));\n \t}\n \n@@ -2158,7 +2158,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\t\t       get_num_chunks(cf)),\n \t\t\t    get_num_chunks(cf));\n \t\tctx->progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\tprogress_title.buf,\n \t\t\tst_mult(get_num_chunks(cf), ctx->commits.nr));\n \t}\n@@ -2216,7 +2216,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\t}\n \n \t\tfree(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);\n-\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(hash_to_hex(file_hash));\n+\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] =\n+\t\t\txstrdup(hash_to_hex_algop(file_hash, ctx->r->hash_algo));\n \t\tfinal_graph_name = get_split_graph_filename(ctx->odb_source,\n \t\t\t\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);\n \t\tfree(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1]);\n@@ -2370,7 +2371,7 @@ static void sort_and_scan_merged_commits(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Scanning merged commits\"),\n \t\t\t\t\tctx->commits.nr);\n \n@@ -2415,7 +2416,7 @@ static void merge_commit_graphs(struct write_commit_graph_context *ctx)\n \t\tcurrent_graph_number--;\n \n \t\tif (ctx->report_progress)\n-\t\t\tctx->progress = start_delayed_progress(the_repository,\n+\t\t\tctx->progress = start_delayed_progress(ctx->r,\n \t\t\t\t\t\t\t       _(\"Merging commit-graph\"), 0);\n \n \t\tmerge_commit_graph(ctx, g);\n@@ -2518,7 +2519,7 @@ int write_commit_graph(struct odb_source *source,\n \t\t       enum commit_graph_write_flags flags,\n \t\t       const struct commit_graph_opts *opts)\n {\n-\tstruct repository *r = the_repository;\n+\tstruct repository *r = source->odb->repo;\n \tstruct write_commit_graph_context ctx = {\n \t\t.r = r,\n \t\t.odb_source = source,\n@@ -2618,14 +2619,14 @@ int write_commit_graph(struct odb_source *source,\n \t\t\treplace = ctx.opts->split_flags & COMMIT_GRAPH_SPLIT_REPLACE;\n \t}\n \n-\tctx.approx_nr_objects = repo_approximate_object_count(the_repository);\n+\tctx.approx_nr_objects = repo_approximate_object_count(r);\n \n \tif (ctx.append && ctx.r->objects->commit_graph) {\n \t\tstruct commit_graph *g = ctx.r->objects->commit_graph;\n \t\tfor (i = 0; i < g->num_commits; i++) {\n \t\t\tstruct object_id oid;\n \t\t\toidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n-\t\t\t\tthe_repository->hash_algo);\n+\t\t\t\tr->hash_algo);\n \t\t\toid_array_append(&ctx.oids, &oid);\n \t\t}\n \t}\n@@ -2733,7 +2734,7 @@ static void graph_report(const char *fmt, ...)\n \n static int commit_graph_checksum_valid(struct commit_graph *g)\n {\n-\treturn hashfile_checksum_valid(the_repository->hash_algo,\n+\treturn hashfile_checksum_valid(g->hash_algo,\n \t\t\t\t       g->data, g->data_len);\n }\n \n@@ -2756,7 +2757,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\tstruct commit *graph_commit;\n \n \t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n-\t\t\tthe_repository->hash_algo);\n+\t\t\tg->hash_algo);\n \n \t\tif (i && oidcmp(&prev_oid, &cur_oid) >= 0)\n \t\t\tgraph_report(_(\"commit-graph has incorrect OID order: %s then %s\"),\n@@ -2801,7 +2802,7 @@ static int verify_one_commit_graph(struct repository *r,\n \n \t\tdisplay_progress(progress, ++(*seen));\n \t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n-\t\t\tthe_repository->hash_algo);\n+\t\t\tg->hash_algo);\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\n \t\todb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r));\n@@ -2905,7 +2906,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n \t\tif (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW))\n \t\t\ttotal += g->num_commits_in_base;\n \n-\t\tprogress = start_progress(the_repository,\n+\t\tprogress = start_progress(r,\n \t\t\t\t\t  _(\"Verifying commits in commit graph\"),\n \t\t\t\t\t  total);\n \t}\ndiff --git a/commit-graph.h b/commit-graph.h\nindex 5f417f7666..ba2856437f 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -21,7 +21,7 @@\n  * call this method oustide of a builtin, and only if you know what\n  * you are doing!\n  */\n-void git_test_write_commit_graph_or_die(void);\n+void git_test_write_commit_graph_or_die(struct odb_source *source);\n \n struct commit;\n struct bloom_filter_settings;\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523724","messageId":"20250807-b4-pks-commit-graph-wo-the-repository-v3-10-82edef830a1e@pks.im","threadId":"63902","inReplyTo":"20250807-b4-pks-commit-graph-wo-the-repository-v3-0-82edef830a1e@pks.im","subject":"[PATCH v3 10/10] commit-graph: stop passing in redundant repository","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-07T08:04:52Z","receivedAt":"2025-08-07T08:05:22Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Many of the commit-graph related functions take in both a repository and\nthe object database source (directly or via `struct commit_graph`) for\nwhich we are supposed to load such a commit-graph. In the best case this\ninformation is simply redundant as the source already contains a\nreference to its owning object database, which in turn has a reference\nto its repository. In the worst case this information could even\nmismatch when passing in a source that doesn't belong to the same\nrepository.\n\nRefactor the code so that we only pass in the object database source in\nthose cases.\n\nThere is one exception though, namely `load_commit_graph_chain_fd_st()`,\nwhich is responsible for loading a commit-graph chain. It is expected\nthat parts of the commit-graph chain aren't located in the same object\nsource as the chain file itself, but in a different one. Consequently,\nthis function doesn't work on the source level but on the database level\ninstead.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit-graph.c     |   6 +--\n commit-graph.c             | 120 +++++++++++++++++++--------------------------\n commit-graph.h             |  12 ++---\n t/helper/test-read-graph.c |   2 +-\n 4 files changed, 59 insertions(+), 81 deletions(-)\n\ndiff --git a/builtin/commit-graph.c b/builtin/commit-graph.c\nindex 680b03a83a..1b80993b2d 100644\n--- a/builtin/commit-graph.c\n+++ b/builtin/commit-graph.c\n@@ -121,15 +121,15 @@ static int graph_verify(int argc, const char **argv, const char *prefix,\n \tif (opened == OPENED_NONE)\n \t\treturn 0;\n \telse if (opened == OPENED_GRAPH)\n-\t\tgraph = load_commit_graph_one_fd_st(the_repository, fd, &st, source);\n+\t\tgraph = load_commit_graph_one_fd_st(source, fd, &st);\n \telse\n-\t\tgraph = load_commit_graph_chain_fd_st(the_repository, fd, &st,\n+\t\tgraph = load_commit_graph_chain_fd_st(the_repository->objects, fd, &st,\n \t\t\t\t\t\t      &incomplete_chain);\n \n \tif (!graph)\n \t\treturn 1;\n \n-\tret = verify_commit_graph(the_repository, graph, flags);\n+\tret = verify_commit_graph(graph, flags);\n \tfree_commit_graph(graph);\n \n \tif (incomplete_chain) {\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 8e087fc4e6..b4a2924889 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -250,9 +250,8 @@ int open_commit_graph(const char *graph_file, int *fd, struct stat *st)\n \treturn 1;\n }\n \n-struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n-\t\t\t\t\t\t int fd, struct stat *st,\n-\t\t\t\t\t\t struct odb_source *source)\n+struct commit_graph *load_commit_graph_one_fd_st(struct odb_source *source,\n+\t\t\t\t\t\t int fd, struct stat *st)\n {\n \tvoid *graph_map;\n \tsize_t graph_size;\n@@ -260,7 +259,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \n \tgraph_size = xsize_t(st->st_size);\n \n-\tif (graph_size < graph_min_size(r->hash_algo)) {\n+\tif (graph_size < graph_min_size(source->odb->repo->hash_algo)) {\n \t\tclose(fd);\n \t\terror(_(\"commit-graph file is too small\"));\n \t\treturn NULL;\n@@ -268,7 +267,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \tgraph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);\n \tclose(fd);\n \n-\tret = parse_commit_graph(r, graph_map, graph_size);\n+\tret = parse_commit_graph(source->odb->repo, graph_map, graph_size);\n \tif (ret)\n \t\tret->odb_source = source;\n \telse\n@@ -488,11 +487,9 @@ struct commit_graph *parse_commit_graph(struct repository *r,\n \treturn NULL;\n }\n \n-static struct commit_graph *load_commit_graph_one(struct repository *r,\n-\t\t\t\t\t\t  const char *graph_file,\n-\t\t\t\t\t\t  struct odb_source *source)\n+static struct commit_graph *load_commit_graph_one(struct odb_source *source,\n+\t\t\t\t\t\t  const char *graph_file)\n {\n-\n \tstruct stat st;\n \tint fd;\n \tstruct commit_graph *g;\n@@ -501,19 +498,17 @@ static struct commit_graph *load_commit_graph_one(struct repository *r,\n \tif (!open_ok)\n \t\treturn NULL;\n \n-\tg = load_commit_graph_one_fd_st(r, fd, &st, source);\n-\n+\tg = load_commit_graph_one_fd_st(source, fd, &st);\n \tif (g)\n \t\tg->filename = xstrdup(graph_file);\n \n \treturn g;\n }\n \n-static struct commit_graph *load_commit_graph_v1(struct repository *r,\n-\t\t\t\t\t\t struct odb_source *source)\n+static struct commit_graph *load_commit_graph_v1(struct odb_source *source)\n {\n \tchar *graph_name = get_commit_graph_filename(source);\n-\tstruct commit_graph *g = load_commit_graph_one(r, graph_name, source);\n+\tstruct commit_graph *g = load_commit_graph_one(source, graph_name);\n \tfree(graph_name);\n \n \treturn g;\n@@ -640,7 +635,7 @@ int open_commit_graph_chain(const char *chain_file,\n \treturn 1;\n }\n \n-struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n+struct commit_graph *load_commit_graph_chain_fd_st(struct object_database *odb,\n \t\t\t\t\t\t   int fd, struct stat *st,\n \t\t\t\t\t\t   int *incomplete_chain)\n {\n@@ -651,10 +646,10 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \tFILE *fp = xfdopen(fd, \"r\");\n \tsize_t count;\n \n-\tcount = st->st_size / (r->hash_algo->hexsz + 1);\n+\tcount = st->st_size / (odb->repo->hash_algo->hexsz + 1);\n \tCALLOC_ARRAY(oids, count);\n \n-\todb_prepare_alternates(r->objects);\n+\todb_prepare_alternates(odb);\n \n \tfor (size_t i = 0; i < count; i++) {\n \t\tstruct odb_source *source;\n@@ -662,7 +657,7 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \t\tif (strbuf_getline_lf(&line, fp) == EOF)\n \t\t\tbreak;\n \n-\t\tif (get_oid_hex_algop(line.buf, &oids[i], r->hash_algo)) {\n+\t\tif (get_oid_hex_algop(line.buf, &oids[i], odb->repo->hash_algo)) {\n \t\t\twarning(_(\"invalid commit-graph chain: line '%s' not a hash\"),\n \t\t\t\tline.buf);\n \t\t\tvalid = 0;\n@@ -670,9 +665,9 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \t\t}\n \n \t\tvalid = 0;\n-\t\tfor (source = r->objects->sources; source; source = source->next) {\n+\t\tfor (source = odb->sources; source; source = source->next) {\n \t\t\tchar *graph_name = get_split_graph_filename(source, line.buf);\n-\t\t\tstruct commit_graph *g = load_commit_graph_one(r, graph_name, source);\n+\t\t\tstruct commit_graph *g = load_commit_graph_one(source, graph_name);\n \n \t\t\tfree(graph_name);\n \n@@ -705,45 +700,33 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \treturn graph_chain;\n }\n \n-static struct commit_graph *load_commit_graph_chain(struct repository *r,\n-\t\t\t\t\t\t    struct odb_source *source)\n+static struct commit_graph *load_commit_graph_chain(struct odb_source *source)\n {\n \tchar *chain_file = get_commit_graph_chain_filename(source);\n \tstruct stat st;\n \tint fd;\n \tstruct commit_graph *g = NULL;\n \n-\tif (open_commit_graph_chain(chain_file, &fd, &st, r->hash_algo)) {\n+\tif (open_commit_graph_chain(chain_file, &fd, &st, source->odb->repo->hash_algo)) {\n \t\tint incomplete;\n \t\t/* ownership of fd is taken over by load function */\n-\t\tg = load_commit_graph_chain_fd_st(r, fd, &st, &incomplete);\n+\t\tg = load_commit_graph_chain_fd_st(source->odb, fd, &st, &incomplete);\n \t}\n \n \tfree(chain_file);\n \treturn g;\n }\n \n-struct commit_graph *read_commit_graph_one(struct repository *r,\n-\t\t\t\t\t   struct odb_source *source)\n+struct commit_graph *read_commit_graph_one(struct odb_source *source)\n {\n-\tstruct commit_graph *g = load_commit_graph_v1(r, source);\n+\tstruct commit_graph *g = load_commit_graph_v1(source);\n \n \tif (!g)\n-\t\tg = load_commit_graph_chain(r, source);\n+\t\tg = load_commit_graph_chain(source);\n \n \treturn g;\n }\n \n-static void prepare_commit_graph_one(struct repository *r,\n-\t\t\t\t     struct odb_source *source)\n-{\n-\n-\tif (r->objects->commit_graph)\n-\t\treturn;\n-\n-\tr->objects->commit_graph = read_commit_graph_one(r, source);\n-}\n-\n /*\n  * Return 1 if commit_graph is non-NULL, and 0 otherwise.\n  *\n@@ -784,10 +767,12 @@ static int prepare_commit_graph(struct repository *r)\n \t\treturn 0;\n \n \todb_prepare_alternates(r->objects);\n-\tfor (source = r->objects->sources;\n-\t     !r->objects->commit_graph && source;\n-\t     source = source->next)\n-\t\tprepare_commit_graph_one(r, source);\n+\tfor (source = r->objects->sources; source; source = source->next) {\n+\t\tr->objects->commit_graph = read_commit_graph_one(source);\n+\t\tif (r->objects->commit_graph)\n+\t\t\tbreak;\n+\t}\n+\n \treturn !!r->objects->commit_graph;\n }\n \n@@ -872,8 +857,7 @@ static void load_oid_from_graph(struct commit_graph *g,\n \t\tg->hash_algo);\n }\n \n-static struct commit_list **insert_parent_or_die(struct repository *r,\n-\t\t\t\t\t\t struct commit_graph *g,\n+static struct commit_list **insert_parent_or_die(struct commit_graph *g,\n \t\t\t\t\t\t uint32_t pos,\n \t\t\t\t\t\t struct commit_list **pptr)\n {\n@@ -884,7 +868,7 @@ static struct commit_list **insert_parent_or_die(struct repository *r,\n \t\tdie(\"invalid parent position %\"PRIu32, pos);\n \n \tload_oid_from_graph(g, pos, &oid);\n-\tc = lookup_commit(r, &oid);\n+\tc = lookup_commit(g->odb_source->odb->repo, &oid);\n \tif (!c)\n \t\tdie(_(\"could not find commit %s\"), oid_to_hex(&oid));\n \tcommit_graph_data_at(c)->graph_pos = pos;\n@@ -940,8 +924,7 @@ static inline void set_commit_tree(struct commit *c, struct tree *t)\n \tc->maybe_tree = t;\n }\n \n-static int fill_commit_in_graph(struct repository *r,\n-\t\t\t\tstruct commit *item,\n+static int fill_commit_in_graph(struct commit *item,\n \t\t\t\tstruct commit_graph *g, uint32_t pos)\n {\n \tuint32_t edge_value;\n@@ -967,13 +950,13 @@ static int fill_commit_in_graph(struct repository *r,\n \tedge_value = get_be32(commit_data + g->hash_algo->rawsz);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n-\tpptr = insert_parent_or_die(r, g, edge_value, pptr);\n+\tpptr = insert_parent_or_die(g, edge_value, pptr);\n \n \tedge_value = get_be32(commit_data + g->hash_algo->rawsz + 4);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n \tif (!(edge_value & GRAPH_EXTRA_EDGES_NEEDED)) {\n-\t\tpptr = insert_parent_or_die(r, g, edge_value, pptr);\n+\t\tpptr = insert_parent_or_die(g, edge_value, pptr);\n \t\treturn 1;\n \t}\n \n@@ -988,7 +971,7 @@ static int fill_commit_in_graph(struct repository *r,\n \t\t}\n \t\tedge_value = get_be32(g->chunk_extra_edges +\n \t\t\t\t      sizeof(uint32_t) * parent_data_pos);\n-\t\tpptr = insert_parent_or_die(r, g,\n+\t\tpptr = insert_parent_or_die(g,\n \t\t\t\t\t    edge_value & GRAPH_EDGE_LAST_MASK,\n \t\t\t\t\t    pptr);\n \t\tparent_data_pos++;\n@@ -1054,14 +1037,13 @@ struct commit *lookup_commit_in_graph(struct repository *repo, const struct obje\n \tif (commit->object.parsed)\n \t\treturn commit;\n \n-\tif (!fill_commit_in_graph(repo, commit, repo->objects->commit_graph, pos))\n+\tif (!fill_commit_in_graph(commit, repo->objects->commit_graph, pos))\n \t\treturn NULL;\n \n \treturn commit;\n }\n \n-static int parse_commit_in_graph_one(struct repository *r,\n-\t\t\t\t     struct commit_graph *g,\n+static int parse_commit_in_graph_one(struct commit_graph *g,\n \t\t\t\t     struct commit *item)\n {\n \tuint32_t pos;\n@@ -1070,7 +1052,7 @@ static int parse_commit_in_graph_one(struct repository *r,\n \t\treturn 1;\n \n \tif (find_commit_pos_in_graph(item, g, &pos))\n-\t\treturn fill_commit_in_graph(r, item, g, pos);\n+\t\treturn fill_commit_in_graph(item, g, pos);\n \n \treturn 0;\n }\n@@ -1087,7 +1069,7 @@ int parse_commit_in_graph(struct repository *r, struct commit *item)\n \n \tif (!prepare_commit_graph(r))\n \t\treturn 0;\n-\treturn parse_commit_in_graph_one(r, r->objects->commit_graph, item);\n+\treturn parse_commit_in_graph_one(r->objects->commit_graph, item);\n }\n \n void load_commit_graph_info(struct repository *r, struct commit *item)\n@@ -1097,8 +1079,7 @@ void load_commit_graph_info(struct repository *r, struct commit *item)\n \t\tfill_commit_graph_info(item, r->objects->commit_graph, pos);\n }\n \n-static struct tree *load_tree_for_commit(struct repository *r,\n-\t\t\t\t\t struct commit_graph *g,\n+static struct tree *load_tree_for_commit(struct commit_graph *g,\n \t\t\t\t\t struct commit *c)\n {\n \tstruct object_id oid;\n@@ -1113,13 +1094,12 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\t\t\tgraph_pos - g->num_commits_in_base);\n \n \toidread(&oid, commit_data, g->hash_algo);\n-\tset_commit_tree(c, lookup_tree(r, &oid));\n+\tset_commit_tree(c, lookup_tree(g->odb_source->odb->repo, &oid));\n \n \treturn c->maybe_tree;\n }\n \n-static struct tree *get_commit_tree_in_graph_one(struct repository *r,\n-\t\t\t\t\t\t struct commit_graph *g,\n+static struct tree *get_commit_tree_in_graph_one(struct commit_graph *g,\n \t\t\t\t\t\t const struct commit *c)\n {\n \tif (c->maybe_tree)\n@@ -1127,12 +1107,12 @@ static struct tree *get_commit_tree_in_graph_one(struct repository *r,\n \tif (commit_graph_position(c) == COMMIT_NOT_FROM_GRAPH)\n \t\tBUG(\"get_commit_tree_in_graph_one called from non-commit-graph commit\");\n \n-\treturn load_tree_for_commit(r, g, (struct commit *)c);\n+\treturn load_tree_for_commit(g, (struct commit *)c);\n }\n \n struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit *c)\n {\n-\treturn get_commit_tree_in_graph_one(r, r->objects->commit_graph, c);\n+\treturn get_commit_tree_in_graph_one(r->objects->commit_graph, c);\n }\n \n struct packed_commit_list {\n@@ -2738,11 +2718,11 @@ static int commit_graph_checksum_valid(struct commit_graph *g)\n \t\t\t\t       g->data, g->data_len);\n }\n \n-static int verify_one_commit_graph(struct repository *r,\n-\t\t\t\t   struct commit_graph *g,\n+static int verify_one_commit_graph(struct commit_graph *g,\n \t\t\t\t   struct progress *progress,\n \t\t\t\t   uint64_t *seen)\n {\n+\tstruct repository *r = g->odb_source->odb->repo;\n \tuint32_t i, cur_fanout_pos = 0;\n \tstruct object_id prev_oid, cur_oid;\n \tstruct commit *seen_gen_zero = NULL;\n@@ -2776,7 +2756,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\t}\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\n-\t\tif (!parse_commit_in_graph_one(r, g, graph_commit))\n+\t\tif (!parse_commit_in_graph_one(g, graph_commit))\n \t\t\tgraph_report(_(\"failed to parse commit %s from commit-graph\"),\n \t\t\t\t     oid_to_hex(&cur_oid));\n \t}\n@@ -2812,7 +2792,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\t\tcontinue;\n \t\t}\n \n-\t\tif (!oideq(&get_commit_tree_in_graph_one(r, g, graph_commit)->object.oid,\n+\t\tif (!oideq(&get_commit_tree_in_graph_one(g, graph_commit)->object.oid,\n \t\t\t   get_commit_tree_oid(odb_commit)))\n \t\t\tgraph_report(_(\"root tree OID for commit %s in commit-graph is %s != %s\"),\n \t\t\t\t     oid_to_hex(&cur_oid),\n@@ -2830,7 +2810,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\t\t}\n \n \t\t\t/* parse parent in case it is in a base graph */\n-\t\t\tparse_commit_in_graph_one(r, g, graph_parents->item);\n+\t\t\tparse_commit_in_graph_one(g, graph_parents->item);\n \n \t\t\tif (!oideq(&graph_parents->item->object.oid, &odb_parents->item->object.oid))\n \t\t\t\tgraph_report(_(\"commit-graph parent for %s is %s != %s\"),\n@@ -2890,7 +2870,7 @@ static int verify_one_commit_graph(struct repository *r,\n \treturn verify_commit_graph_error;\n }\n \n-int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n+int verify_commit_graph(struct commit_graph *g, int flags)\n {\n \tstruct progress *progress = NULL;\n \tint local_error = 0;\n@@ -2906,13 +2886,13 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n \t\tif (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW))\n \t\t\ttotal += g->num_commits_in_base;\n \n-\t\tprogress = start_progress(r,\n+\t\tprogress = start_progress(g->odb_source->odb->repo,\n \t\t\t\t\t  _(\"Verifying commits in commit graph\"),\n \t\t\t\t\t  total);\n \t}\n \n \tfor (; g; g = g->base_graph) {\n-\t\tlocal_error |= verify_one_commit_graph(r, g, progress, &seen);\n+\t\tlocal_error |= verify_one_commit_graph(g, progress, &seen);\n \t\tif (flags & COMMIT_GRAPH_VERIFY_SHALLOW)\n \t\t\tbreak;\n \t}\ndiff --git a/commit-graph.h b/commit-graph.h\nindex ba2856437f..269f86be56 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -114,14 +114,12 @@ struct commit_graph {\n \tstruct bloom_filter_settings *bloom_filter_settings;\n };\n \n-struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n-\t\t\t\t\t\t int fd, struct stat *st,\n-\t\t\t\t\t\t struct odb_source *source);\n-struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n+struct commit_graph *load_commit_graph_one_fd_st(struct odb_source *source,\n+\t\t\t\t\t\t int fd, struct stat *st);\n+struct commit_graph *load_commit_graph_chain_fd_st(struct object_database *odb,\n \t\t\t\t\t\t   int fd, struct stat *st,\n \t\t\t\t\t\t   int *incomplete_chain);\n-struct commit_graph *read_commit_graph_one(struct repository *r,\n-\t\t\t\t\t   struct odb_source *source);\n+struct commit_graph *read_commit_graph_one(struct odb_source *source);\n \n struct repo_settings;\n \n@@ -185,7 +183,7 @@ int write_commit_graph(struct odb_source *source,\n \n #define COMMIT_GRAPH_VERIFY_SHALLOW\t(1 << 0)\n \n-int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags);\n+int verify_commit_graph(struct commit_graph *g, int flags);\n \n void close_commit_graph(struct object_database *);\n void free_commit_graph(struct commit_graph *);\ndiff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c\nindex ef5339bbee..6a5f64e473 100644\n--- a/t/helper/test-read-graph.c\n+++ b/t/helper/test-read-graph.c\n@@ -81,7 +81,7 @@ int cmd__read_graph(int argc, const char **argv)\n \n \tprepare_repo_settings(the_repository);\n \n-\tgraph = read_commit_graph_one(the_repository, source);\n+\tgraph = read_commit_graph_one(source);\n \tif (!graph) {\n \t\tret = 1;\n \t\tgoto done;\n\n-- \n2.51.0.rc0.215.g125493bb4a.dirty\n\n"},{"id":"523786","messageId":"xmqqv7mykb65.fsf@gitster.g","threadId":"63902","inReplyTo":"20250807-b4-pks-commit-graph-wo-the-repository-v3-3-82edef830a1e@pks.im","subject":"Re: [PATCH v3 03/10] commit-graph: fix type for some write options","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-08-07T22:40:50Z","receivedAt":"2025-08-07T22:40:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> The options \"max-commits\" and \"size-multiple\" are both supposed to be\n> positive integers and are documented as such, but we use a signed\n> integer field to store them. This causes sign comparison warnings in\n> `split_graph_merge_strategy()` because we end up comparing the option\n> values with the observed number of commits.\n>\n> Fix the issue by converting the fields to be unsigned and convert the\n> options to use `OPT_UNSIGNED()` accordingly. This macro has only been\n> introduced recently, which might explain why the option values were\n> signed in the first place.\n\nThese are platform natural \"int\" from their inception at c2bc6e6a\n(commit-graph: create options for split files, 2019-06-18), which\nway predates the recent push to appease -Wsign-compare, so yes, it\ndoes explain it.  But because the developer who wrote it in the\nfirst place is around and with us, why not ask them instead of\nspeculating?\n\nAs the max_commits member is comparable to 4-byte network byte order\ninteger that is .num_commits in the file, using platform natural\n\"int\" or int32_t is not correct, because you may not be able to tell\nthe command to hold 3 billion objects before splitting, even though\nthe underlying file format does support such settings.  It has to be\nuint32_t or wider (but if it is wider, you'd need to be prepared to\ncorrectly compare max_commits with num_commits, and take an overly\nlarge max as \"unlimited\", or something).  And unsigned usually is at\nleast that wide, so the change may be justified.  I do not see a\nreason why we want to avoid using uint32_t, though.\n\nAs to size_multiple, it appears to me that the number is really\ndesigned to be a small integer (for which even 100 is probably way\ntoo many), so I do not see any reason to insist it to be unsigned.\nEven \"short\" _ought_ to do fine.  And if our macros and compiler\nsettings do not support it well and DEVELOPER=YesPlease build\ncomplain, that is what we need to fix.  Papering over the problem by\nusing unnecessarily wide type, or by using signedness that happens\nto squelch the misguided compiler warnings, is skirting around it.\n\nIf there is any bug, it is st_mult(size_mult, num_commit) and the\ncompiler warning that complains about its CPP expansion, even though\nit should be able to ensure that \"int size_mult\" (or \"short\nsize_mult\") that gets promoted to unsigned to match uint32_t\nnum_commit would not overflow the unsigned multiplication.\n\nSo my take on this change is that \"fix type for ...\" on the subject\nline greatly misrepresents what this change does.  It smells to me\nthat \"squelch -Wsign-compare warnings\" would be closer to what is\nhappening.\n\nIt really is arithmetic overflowing and wrapping around that we want\nto be careful about.  -Wsign-compare alone is not doing a good job\nto do so, is it?\n"},{"id":"523787","messageId":"xmqqpld6kb4t.fsf@gitster.g","threadId":"63902","inReplyTo":"aJRP_muuzCAy3mzF@pks.im","subject":"Re: [PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-08-07T22:41:38Z","receivedAt":"2025-08-07T22:41:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> Yup, fully agreed, and this is a good reason why it should be signed. In\n> the case at hand though we never use such sentinel values, I think\n> making that explicit by using an unsigned type is a good thing as it\n> tells the reader that \"Yup, no sentinels involved, it's a plain counter\n> from 0 to $NUM_ENTRIES\".\n\nI do not think such a \"statement\" has much values, especially the\nright $NUM_ENTRIES is different for specific cases and is not\nexpressed anywhere.\n\nAlso, by making it explicit, such a move is also making it explicit\nthat we want to close the door for certain future evolution of the\ncode paths involved.  I.e. anything that starts to require the\nmember or the variable to use a sentinel value is unwelcome.\n\nSo, I am not sure if I buy the above as a justification for this\nchange.\n"},{"id":"523910","messageId":"aJmkZYtQt_KRHCeD@pks.im","threadId":"63902","inReplyTo":"xmqqpld6kb4t.fsf@gitster.g","subject":"Re: [PATCH 2/9] commit-graph: stop using signed integers to count bloom filters","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-11T08:05:57Z","receivedAt":"2025-08-11T08:06:11Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Thu, Aug 07, 2025 at 03:41:38PM -0700, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> > Yup, fully agreed, and this is a good reason why it should be signed. In\n> > the case at hand though we never use such sentinel values, I think\n> > making that explicit by using an unsigned type is a good thing as it\n> > tells the reader that \"Yup, no sentinels involved, it's a plain counter\n> > from 0 to $NUM_ENTRIES\".\n> \n> I do not think such a \"statement\" has much values, especially the\n> right $NUM_ENTRIES is different for specific cases and is not\n> expressed anywhere.\n> \n> Also, by making it explicit, such a move is also making it explicit\n> that we want to close the door for certain future evolution of the\n> code paths involved.  I.e. anything that starts to require the\n> member or the variable to use a sentinel value is unwelcome.\n\nI think that's actually a good thing. If we wanted to start using a\nsentinel value we'd have to change the type to be signed. Combined with\n-Wsign-compare this would then alert us of cases where we compare this\ncounter with an unsigned index, which are exactly all the sites where we\nmight have to adjust the code to take into account the new sentinel\nvalue.\n\nPatrick\n"},{"id":"523911","messageId":"aJmouVRjPrBlLvrT@pks.im","threadId":"63902","inReplyTo":"xmqqv7mykb65.fsf@gitster.g","subject":"Re: [PATCH v3 03/10] commit-graph: fix type for some write options","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-11T08:24:25Z","receivedAt":"2025-08-11T08:24:31Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Thu, Aug 07, 2025 at 03:40:50PM -0700, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> > The options \"max-commits\" and \"size-multiple\" are both supposed to be\n> > positive integers and are documented as such, but we use a signed\n> > integer field to store them. This causes sign comparison warnings in\n> > `split_graph_merge_strategy()` because we end up comparing the option\n> > values with the observed number of commits.\n> >\n> > Fix the issue by converting the fields to be unsigned and convert the\n> > options to use `OPT_UNSIGNED()` accordingly. This macro has only been\n> > introduced recently, which might explain why the option values were\n> > signed in the first place.\n> \n> These are platform natural \"int\" from their inception at c2bc6e6a\n> (commit-graph: create options for split files, 2019-06-18), which\n> way predates the recent push to appease -Wsign-compare, so yes, it\n> does explain it.  But because the developer who wrote it in the\n> first place is around and with us, why not ask them instead of\n> speculating?\n> \n> As the max_commits member is comparable to 4-byte network byte order\n> integer that is .num_commits in the file, using platform natural\n> \"int\" or int32_t is not correct, because you may not be able to tell\n> the command to hold 3 billion objects before splitting, even though\n> the underlying file format does support such settings.  It has to be\n> uint32_t or wider (but if it is wider, you'd need to be prepared to\n> correctly compare max_commits with num_commits, and take an overly\n> large max as \"unlimited\", or something).  And unsigned usually is at\n> least that wide, so the change may be justified.  I do not see a\n> reason why we want to avoid using uint32_t, though.\n\nUsing `uint32_t` might cause regressions on some platforms. If for\nexample a signed integer was 64 bits on certain platforms and we\nrestrict it to `uint32_t` then we'd now refuse to take any values\nbetween `2^32` and `2^63`, even though those are valid values that we\naccepted beforehand. So if somebody was using any such value to say\n\"make this essentially unlimited\" then we'd now die.\n\nBut by using `unsigned` we avoid this pitfall, as we only extend the\nrange of accepted valid values.\n\n> As to size_multiple, it appears to me that the number is really\n> designed to be a small integer (for which even 100 is probably way\n> too many), so I do not see any reason to insist it to be unsigned.\n> Even \"short\" _ought_ to do fine.  And if our macros and compiler\n> settings do not support it well and DEVELOPER=YesPlease build\n> complain, that is what we need to fix.  Papering over the problem by\n> using unnecessarily wide type, or by using signedness that happens\n> to squelch the misguided compiler warnings, is skirting around it.\n\nYeah, it is. At one point I was pondering whether we should extend our\nparse-options interface to allow restricting to arbitrary values like\n100. I even implemented all of this, but ultimately discarded it because\nit wasn't easy to decide where we can retroactively harden accepted\nvalues without causing regressions.\n\nWhile large values for options may frequently be unreasonable, it\nwouldn't be the first time that I see users doing unreasonable things\nintentfully. And sometimes the outcome is even something sensible.\n\nPatrick\n"},{"id":"524229","messageId":"20250815-b4-pks-commit-graph-wo-the-repository-v4-0-b6b651178cce@pks.im","threadId":"63902","inReplyTo":"20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im","subject":"[PATCH v4 0/6] commit-graph: remove reliance on global state","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-15T05:49:46Z","receivedAt":"2025-08-15T05:49:54Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Hi,\n\nthis patch series is another step on our long road towards not having\nglobal state. In addition to that, as commit-graphs are part of the\nobject database layer, this is also another step towards pluggable\nobject databases.\n\nChanges in v2:\n  - Use `unsigned` instead of `size_t` to count number of Bloom filters.\n  - Use `uint32_t` instead of `size_t` for number of commit graphs,\n    as this type is also used to iterate through this count already.\n  - Refactor `parse_commit_graph()` to take a repository instead of both\n    repo settings and a hash algo.\n  - Link to v1: https://lore.kernel.org/r/20250804-b4-pks-commit-graph-wo-the-repository-v1-0-850d626eb2e8@pks.im\n\nChanges in v3:\n  - Use `unsigned` for commit-graph options instead of `size_t`.\n  - Link to v2: https://lore.kernel.org/r/20250806-b4-pks-commit-graph-wo-the-repository-v2-0-911bae638e61@pks.im\n\nChanges in v4:\n  - Drop the patches that fix `-Wsign-compare` warnings.\n  - Link to v3: https://lore.kernel.org/r/20250807-b4-pks-commit-graph-wo-the-repository-v3-0-82edef830a1e@pks.im\n\nThanks!\n\nPatrick\n\n---\nPatrick Steinhardt (6):\n      commit-graph: stop using `the_hash_algo` via macros\n      commit-graph: store the hash algorithm instead of its length\n      commit-graph: refactor `parse_commit_graph()` to take a repository\n      commit-graph: stop using `the_hash_algo`\n      commit-graph: stop using `the_repository`\n      commit-graph: stop passing in redundant repository\n\n builtin/commit-graph.c       |   9 +-\n builtin/commit.c             |   2 +-\n builtin/merge.c              |   2 +-\n commit-graph.c               | 283 +++++++++++++++++++++----------------------\n commit-graph.h               |  21 ++--\n oss-fuzz/fuzz-commit-graph.c |   6 +-\n t/helper/test-read-graph.c   |   2 +-\n 7 files changed, 157 insertions(+), 168 deletions(-)\n\nRange-diff versus v3:\n\n 1:  26daf74e02 <  -:  ---------- trace2: introduce function to trace unsigned integers\n 2:  646805924e <  -:  ---------- commit-graph: stop using signed integers to count Bloom filters\n 3:  01e38f39cf <  -:  ---------- commit-graph: fix type for some write options\n 4:  a362f63472 <  -:  ---------- commit-graph: fix sign comparison warnings\n 5:  041d9c07a0 =  1:  f7083b7e3b commit-graph: stop using `the_hash_algo` via macros\n 6:  6c1fa6be4f =  2:  336e35e93b commit-graph: store the hash algorithm instead of its length\n 7:  ed04f7b787 =  3:  1446e1d66f commit-graph: refactor `parse_commit_graph()` to take a repository\n 8:  1eb6316e8d !  4:  368e5ada3e commit-graph: stop using `the_hash_algo`\n    @@ commit-graph.c: int open_commit_graph_chain(const char *chain_file,\n      \t\tclose(*fd);\n      \t\treturn 0;\n      \t}\n    --\tif (st->st_size < (ssize_t) the_hash_algo->hexsz) {\n    -+\tif (st->st_size < (ssize_t) hash_algo->hexsz) {\n    +-\tif (st->st_size < the_hash_algo->hexsz) {\n    ++\tif (st->st_size < hash_algo->hexsz) {\n      \t\tclose(*fd);\n      \t\tif (!st->st_size) {\n      \t\t\t/* treat empty files the same as missing */\n     @@ commit-graph.c: struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n    + \tint i = 0, valid = 1, count;\n      \tFILE *fp = xfdopen(fd, \"r\");\n    - \tsize_t count;\n      \n     -\tcount = st->st_size / (the_hash_algo->hexsz + 1);\n     +\tcount = st->st_size / (r->hash_algo->hexsz + 1);\n    @@ commit-graph.c: static struct tree *load_tree_for_commit(struct repository *r,\n      \n      \toidread(&oid, commit_data, the_repository->hash_algo);\n     @@ commit-graph.c: static int write_graph_chunk_oids(struct hashfile *f,\n    - \n    + \tint count;\n      \tfor (count = 0; count < ctx->commits.nr; count++, list++) {\n      \t\tdisplay_progress(ctx->progress, ++ctx->progress_cnt);\n     -\t\thashwrite(f, (*list)->object.oid.hash, the_hash_algo->rawsz);\n    @@ commit-graph.c: static int write_graph_chunk_data(struct hashfile *f,\n      \n      \t\tparent = (*list)->parents;\n      \n    -@@ commit-graph.c: static size_t write_graph_chunk_base_1(struct hashfile *f,\n    +@@ commit-graph.c: static int write_graph_chunk_base_1(struct hashfile *f,\n      \t\treturn 0;\n      \n      \tnum = write_graph_chunk_base_1(f, g->base_graph);\n 9:  8d599f5a37 !  5:  a51cccec0d commit-graph: stop using `the_repository`\n    @@ builtin/merge.c: int cmd_merge(int argc,\n      ## commit-graph.c ##\n     @@\n     -#define USE_THE_REPOSITORY_VARIABLE\n    --\n    + #define DISABLE_SIGN_COMPARE_WARNINGS\n    + \n      #include \"git-compat-util.h\"\n    - #include \"config.h\"\n    - #include \"csum-file.h\"\n     @@\n      #include \"tree.h\"\n      #include \"chunk-format.h\"\n10:  41ccdd6da1 !  6:  841d280105 commit-graph: stop passing in redundant repository\n    @@ commit-graph.c: int open_commit_graph_chain(const char *chain_file,\n      \t\t\t\t\t\t   int *incomplete_chain)\n      {\n     @@ commit-graph.c: struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n    + \tint i = 0, valid = 1, count;\n      \tFILE *fp = xfdopen(fd, \"r\");\n    - \tsize_t count;\n      \n     -\tcount = st->st_size / (r->hash_algo->hexsz + 1);\n     +\tcount = st->st_size / (odb->repo->hash_algo->hexsz + 1);\n    @@ commit-graph.c: struct commit_graph *load_commit_graph_chain_fd_st(struct reposi\n     -\todb_prepare_alternates(r->objects);\n     +\todb_prepare_alternates(odb);\n      \n    - \tfor (size_t i = 0; i < count; i++) {\n    + \tfor (i = 0; i < count; i++) {\n      \t\tstruct odb_source *source;\n     @@ commit-graph.c: struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n      \t\tif (strbuf_getline_lf(&line, fp) == EOF)\n\n---\nbase-commit: e813a0200a7121b97fec535f0d0b460b0a33356c\nchange-id: 20250717-b4-pks-commit-graph-wo-the-repository-1dc2cacbc8e3\n\n"},{"id":"524230","messageId":"20250815-b4-pks-commit-graph-wo-the-repository-v4-1-b6b651178cce@pks.im","threadId":"63902","inReplyTo":"20250815-b4-pks-commit-graph-wo-the-repository-v4-0-b6b651178cce@pks.im","subject":"[PATCH v4 1/6] commit-graph: stop using `the_hash_algo` via macros","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-15T05:49:47Z","receivedAt":"2025-08-15T05:49:57Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"We have two macros `GRAPH_DATA_WIDTH` and `GRAPH_MIN_SIZE` that compute\nhash-dependent sizes. They do so by using the global `the_hash_algo`\nvariable though, which we want to get rid of over time.\n\nConvert these macros into functions that accept the hash algorithm as\ninput parameter. Adapt callers accordingly.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 25 ++++++++++++++++---------\n 1 file changed, 16 insertions(+), 9 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex bd7b6f5338..ecd50ea3ff 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -53,8 +53,6 @@ void git_test_write_commit_graph_or_die(void)\n #define GRAPH_CHUNKID_BLOOMDATA 0x42444154 /* \"BDAT\" */\n #define GRAPH_CHUNKID_BASE 0x42415345 /* \"BASE\" */\n \n-#define GRAPH_DATA_WIDTH (the_hash_algo->rawsz + 16)\n-\n #define GRAPH_VERSION_1 0x1\n #define GRAPH_VERSION GRAPH_VERSION_1\n \n@@ -66,8 +64,6 @@ void git_test_write_commit_graph_or_die(void)\n \n #define GRAPH_HEADER_SIZE 8\n #define GRAPH_FANOUT_SIZE (4 * 256)\n-#define GRAPH_MIN_SIZE (GRAPH_HEADER_SIZE + 4 * CHUNK_TOC_ENTRY_SIZE \\\n-\t\t\t+ GRAPH_FANOUT_SIZE + the_hash_algo->rawsz)\n \n #define CORRECTED_COMMIT_DATE_OFFSET_OVERFLOW (1ULL << 31)\n \n@@ -80,6 +76,16 @@ define_commit_slab(topo_level_slab, uint32_t);\n define_commit_slab(commit_pos, int);\n static struct commit_pos commit_pos = COMMIT_SLAB_INIT(1, commit_pos);\n \n+static size_t graph_data_width(const struct git_hash_algo *algop)\n+{\n+\treturn algop->rawsz + 16;\n+}\n+\n+static size_t graph_min_size(const struct git_hash_algo *algop)\n+{\n+\treturn GRAPH_HEADER_SIZE + 4 * CHUNK_TOC_ENTRY_SIZE + GRAPH_FANOUT_SIZE + algop->rawsz;\n+}\n+\n static void set_commit_pos(struct repository *r, const struct object_id *oid)\n {\n \tstatic int32_t max_pos;\n@@ -258,7 +264,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \n \tgraph_size = xsize_t(st->st_size);\n \n-\tif (graph_size < GRAPH_MIN_SIZE) {\n+\tif (graph_size < graph_min_size(the_hash_algo)) {\n \t\tclose(fd);\n \t\terror(_(\"commit-graph file is too small\"));\n \t\treturn NULL;\n@@ -314,7 +320,7 @@ static int graph_read_commit_data(const unsigned char *chunk_start,\n \t\t\t\t  size_t chunk_size, void *data)\n {\n \tstruct commit_graph *g = data;\n-\tif (chunk_size / GRAPH_DATA_WIDTH != g->num_commits)\n+\tif (chunk_size / graph_data_width(the_hash_algo) != g->num_commits)\n \t\treturn error(_(\"commit-graph commit data chunk is wrong size\"));\n \tg->chunk_commit_data = chunk_start;\n \treturn 0;\n@@ -379,7 +385,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \tif (!graph_map)\n \t\treturn NULL;\n \n-\tif (graph_size < GRAPH_MIN_SIZE)\n+\tif (graph_size < graph_min_size(the_hash_algo))\n \t\treturn NULL;\n \n \tdata = (const unsigned char *)graph_map;\n@@ -900,7 +906,7 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \t\tdie(_(\"invalid commit position. commit-graph is likely corrupt\"));\n \n \tlex_index = pos - g->num_commits_in_base;\n-\tcommit_data = g->chunk_commit_data + st_mult(GRAPH_DATA_WIDTH, lex_index);\n+\tcommit_data = g->chunk_commit_data + st_mult(graph_data_width(the_hash_algo), lex_index);\n \n \tgraph_data = commit_graph_data_at(item);\n \tgraph_data->graph_pos = pos;\n@@ -1104,7 +1110,8 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\tg = g->base_graph;\n \n \tcommit_data = g->chunk_commit_data +\n-\t\t\tst_mult(GRAPH_DATA_WIDTH, graph_pos - g->num_commits_in_base);\n+\t\t\tst_mult(graph_data_width(the_hash_algo),\n+\t\t\t\tgraph_pos - g->num_commits_in_base);\n \n \toidread(&oid, commit_data, the_repository->hash_algo);\n \tset_commit_tree(c, lookup_tree(r, &oid));\n\n-- \n2.51.0.rc1.215.g0f929dcec7.dirty\n\n"},{"id":"524231","messageId":"20250815-b4-pks-commit-graph-wo-the-repository-v4-2-b6b651178cce@pks.im","threadId":"63902","inReplyTo":"20250815-b4-pks-commit-graph-wo-the-repository-v4-0-b6b651178cce@pks.im","subject":"[PATCH v4 2/6] commit-graph: store the hash algorithm instead of its length","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-15T05:49:48Z","receivedAt":"2025-08-15T05:49:59Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"The commit-graph stores the length of the hash algorithm it uses. In\nsubsequent commits we'll need to pass the whole hash algorithm around\nthough, which we currently don't have access to.\n\nRefactor the code so that we store the hash algorithm instead of only\nits size.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c | 36 ++++++++++++++++++------------------\n commit-graph.h |  2 +-\n 2 files changed, 19 insertions(+), 19 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex ecd50ea3ff..5053d12534 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -311,7 +311,7 @@ static int graph_read_oid_lookup(const unsigned char *chunk_start,\n {\n \tstruct commit_graph *g = data;\n \tg->chunk_oid_lookup = chunk_start;\n-\tif (chunk_size / g->hash_len != g->num_commits)\n+\tif (chunk_size / g->hash_algo->rawsz != g->num_commits)\n \t\treturn error(_(\"commit-graph OID lookup chunk is the wrong size\"));\n \treturn 0;\n }\n@@ -413,7 +413,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \n \tgraph = alloc_commit_graph();\n \n-\tgraph->hash_len = the_hash_algo->rawsz;\n+\tgraph->hash_algo = the_hash_algo;\n \tgraph->num_chunks = *(unsigned char*)(data + 6);\n \tgraph->data = graph_map;\n \tgraph->data_len = graph_size;\n@@ -478,7 +478,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t\tFREE_AND_NULL(graph->bloom_filter_settings);\n \t}\n \n-\toidread(&graph->oid, graph->data + graph->data_len - graph->hash_len,\n+\toidread(&graph->oid, graph->data + graph->data_len - graph->hash_algo->rawsz,\n \t\tthe_repository->hash_algo);\n \n \tfree_chunkfile(cf);\n@@ -584,7 +584,7 @@ static int add_graph_to_chain(struct commit_graph *g,\n \t\treturn 0;\n \t}\n \n-\tif (g->chunk_base_graphs_size / g->hash_len < n) {\n+\tif (g->chunk_base_graphs_size / g->hash_algo->rawsz < n) {\n \t\twarning(_(\"commit-graph base graphs chunk is too small\"));\n \t\treturn 0;\n \t}\n@@ -594,7 +594,7 @@ static int add_graph_to_chain(struct commit_graph *g,\n \n \t\tif (!cur_g ||\n \t\t    !oideq(&oids[n], &cur_g->oid) ||\n-\t\t    !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_len, n),\n+\t\t    !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_algo->rawsz, n),\n \t\t\t    the_repository->hash_algo)) {\n \t\t\twarning(_(\"commit-graph chain does not match\"));\n \t\t\treturn 0;\n@@ -805,7 +805,7 @@ int generation_numbers_enabled(struct repository *r)\n \t\treturn 0;\n \n \tfirst_generation = get_be32(g->chunk_commit_data +\n-\t\t\t\t    g->hash_len + 8) >> 2;\n+\t\t\t\t    g->hash_algo->rawsz + 8) >> 2;\n \n \treturn !!first_generation;\n }\n@@ -849,7 +849,7 @@ void close_commit_graph(struct object_database *o)\n static int bsearch_graph(struct commit_graph *g, const struct object_id *oid, uint32_t *pos)\n {\n \treturn bsearch_hash(oid->hash, g->chunk_oid_fanout,\n-\t\t\t    g->chunk_oid_lookup, g->hash_len, pos);\n+\t\t\t    g->chunk_oid_lookup, g->hash_algo->rawsz, pos);\n }\n \n static void load_oid_from_graph(struct commit_graph *g,\n@@ -869,7 +869,7 @@ static void load_oid_from_graph(struct commit_graph *g,\n \n \tlex_index = pos - g->num_commits_in_base;\n \n-\toidread(oid, g->chunk_oid_lookup + st_mult(g->hash_len, lex_index),\n+\toidread(oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, lex_index),\n \t\tthe_repository->hash_algo);\n }\n \n@@ -911,8 +911,8 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \tgraph_data = commit_graph_data_at(item);\n \tgraph_data->graph_pos = pos;\n \n-\tdate_high = get_be32(commit_data + g->hash_len + 8) & 0x3;\n-\tdate_low = get_be32(commit_data + g->hash_len + 12);\n+\tdate_high = get_be32(commit_data + g->hash_algo->rawsz + 8) & 0x3;\n+\tdate_low = get_be32(commit_data + g->hash_algo->rawsz + 12);\n \titem->date = (timestamp_t)((date_high << 32) | date_low);\n \n \tif (g->read_generation_data) {\n@@ -930,10 +930,10 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \t\t} else\n \t\t\tgraph_data->generation = item->date + offset;\n \t} else\n-\t\tgraph_data->generation = get_be32(commit_data + g->hash_len + 8) >> 2;\n+\t\tgraph_data->generation = get_be32(commit_data + g->hash_algo->rawsz + 8) >> 2;\n \n \tif (g->topo_levels)\n-\t\t*topo_level_slab_at(g->topo_levels, item) = get_be32(commit_data + g->hash_len + 8) >> 2;\n+\t\t*topo_level_slab_at(g->topo_levels, item) = get_be32(commit_data + g->hash_algo->rawsz + 8) >> 2;\n }\n \n static inline void set_commit_tree(struct commit *c, struct tree *t)\n@@ -957,7 +957,7 @@ static int fill_commit_in_graph(struct repository *r,\n \tfill_commit_graph_info(item, g, pos);\n \n \tlex_index = pos - g->num_commits_in_base;\n-\tcommit_data = g->chunk_commit_data + st_mult(g->hash_len + 16, lex_index);\n+\tcommit_data = g->chunk_commit_data + st_mult(g->hash_algo->rawsz + 16, lex_index);\n \n \titem->object.parsed = 1;\n \n@@ -965,12 +965,12 @@ static int fill_commit_in_graph(struct repository *r,\n \n \tpptr = &item->parents;\n \n-\tedge_value = get_be32(commit_data + g->hash_len);\n+\tedge_value = get_be32(commit_data + g->hash_algo->rawsz);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n \tpptr = insert_parent_or_die(r, g, edge_value, pptr);\n \n-\tedge_value = get_be32(commit_data + g->hash_len + 4);\n+\tedge_value = get_be32(commit_data + g->hash_algo->rawsz + 4);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n \tif (!(edge_value & GRAPH_EXTRA_EDGES_NEEDED)) {\n@@ -2623,7 +2623,7 @@ int write_commit_graph(struct odb_source *source,\n \t\tstruct commit_graph *g = ctx.r->objects->commit_graph;\n \t\tfor (i = 0; i < g->num_commits; i++) {\n \t\t\tstruct object_id oid;\n-\t\t\toidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),\n+\t\t\toidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n \t\t\t\tthe_repository->hash_algo);\n \t\t\toid_array_append(&ctx.oids, &oid);\n \t\t}\n@@ -2754,7 +2754,7 @@ static int verify_one_commit_graph(struct repository *r,\n \tfor (i = 0; i < g->num_commits; i++) {\n \t\tstruct commit *graph_commit;\n \n-\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),\n+\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n \t\t\tthe_repository->hash_algo);\n \n \t\tif (i && oidcmp(&prev_oid, &cur_oid) >= 0)\n@@ -2799,7 +2799,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\ttimestamp_t generation;\n \n \t\tdisplay_progress(progress, ++(*seen));\n-\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_len, i),\n+\t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n \t\t\tthe_repository->hash_algo);\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\ndiff --git a/commit-graph.h b/commit-graph.h\nindex 78ab7b875b..7dc1f2b22b 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -84,7 +84,7 @@ struct commit_graph {\n \tconst unsigned char *data;\n \tsize_t data_len;\n \n-\tunsigned char hash_len;\n+\tconst struct git_hash_algo *hash_algo;\n \tunsigned char num_chunks;\n \tuint32_t num_commits;\n \tstruct object_id oid;\n\n-- \n2.51.0.rc1.215.g0f929dcec7.dirty\n\n"},{"id":"524232","messageId":"20250815-b4-pks-commit-graph-wo-the-repository-v4-3-b6b651178cce@pks.im","threadId":"63902","inReplyTo":"20250815-b4-pks-commit-graph-wo-the-repository-v4-0-b6b651178cce@pks.im","subject":"[PATCH v4 3/6] commit-graph: refactor `parse_commit_graph()` to take a repository","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-15T05:49:49Z","receivedAt":"2025-08-15T05:50:03Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Refactor `parse_commit_graph()` so that it takes a repository instead of\ntaking repository settings. On the one hand this allows us to get rid of\ninstances where we access `the_hash_algo` by using the repository's hash\nalgorithm instead. On the other hand it also allows us to move the call\nof `prepare_repo_settings()` into the function itself.\n\nNote that there's one small catch, as the commit-graph fuzzer calls this\nfunction directly without having a fully functional repository at hand.\nAnd while the fuzzer already initializes `the_repository` with relevant\ninfo, the call to `prepare_repo_settings()` would fail because we don't\nhave a fully-initialized repository.\n\nWork around the issue by also settings `settings.initialized` to pretend\nthat we've already read the settings.\n\nWhile at it, remove the redundant `parse_commit_graph()` declaration in\nthe fuzzer. It was added together with aa658574bf (commit-graph, fuzz:\nadd fuzzer for commit-graph, 2019-01-15), but as we also declared the\nsame function in \"commit-graph.h\" it wasn't ever needed.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n commit-graph.c               | 23 ++++++++++++-----------\n commit-graph.h               |  2 +-\n oss-fuzz/fuzz-commit-graph.c |  6 ++----\n 3 files changed, 15 insertions(+), 16 deletions(-)\n\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 5053d125340..2f314a7407e 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -271,9 +271,8 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \t}\n \tgraph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);\n \tclose(fd);\n-\tprepare_repo_settings(r);\n-\tret = parse_commit_graph(&r->settings, graph_map, graph_size);\n \n+\tret = parse_commit_graph(r, graph_map, graph_size);\n \tif (ret)\n \t\tret->odb_source = source;\n \telse\n@@ -373,7 +372,7 @@ static int graph_read_bloom_data(const unsigned char *chunk_start,\n \treturn 0;\n }\n \n-struct commit_graph *parse_commit_graph(struct repo_settings *s,\n+struct commit_graph *parse_commit_graph(struct repository *r,\n \t\t\t\t\tvoid *graph_map, size_t graph_size)\n {\n \tconst unsigned char *data;\n@@ -385,7 +384,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \tif (!graph_map)\n \t\treturn NULL;\n \n-\tif (graph_size < graph_min_size(the_hash_algo))\n+\tif (graph_size < graph_min_size(r->hash_algo))\n \t\treturn NULL;\n \n \tdata = (const unsigned char *)graph_map;\n@@ -405,22 +404,22 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t}\n \n \thash_version = *(unsigned char*)(data + 5);\n-\tif (hash_version != oid_version(the_hash_algo)) {\n+\tif (hash_version != oid_version(r->hash_algo)) {\n \t\terror(_(\"commit-graph hash version %X does not match version %X\"),\n-\t\t      hash_version, oid_version(the_hash_algo));\n+\t\t      hash_version, oid_version(r->hash_algo));\n \t\treturn NULL;\n \t}\n \n \tgraph = alloc_commit_graph();\n \n-\tgraph->hash_algo = the_hash_algo;\n+\tgraph->hash_algo = r->hash_algo;\n \tgraph->num_chunks = *(unsigned char*)(data + 6);\n \tgraph->data = graph_map;\n \tgraph->data_len = graph_size;\n \n \tif (graph_size < GRAPH_HEADER_SIZE +\n \t\t\t (graph->num_chunks + 1) * CHUNK_TOC_ENTRY_SIZE +\n-\t\t\t GRAPH_FANOUT_SIZE + the_hash_algo->rawsz) {\n+\t\t\t GRAPH_FANOUT_SIZE + r->hash_algo->rawsz) {\n \t\terror(_(\"commit-graph file is too small to hold %u chunks\"),\n \t\t      graph->num_chunks);\n \t\tfree(graph);\n@@ -451,7 +450,9 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \tpair_chunk(cf, GRAPH_CHUNKID_BASE, &graph->chunk_base_graphs,\n \t\t   &graph->chunk_base_graphs_size);\n \n-\tif (s->commit_graph_generation_version >= 2) {\n+\tprepare_repo_settings(r);\n+\n+\tif (r->settings.commit_graph_generation_version >= 2) {\n \t\tread_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA,\n \t\t\t   graph_read_generation_data, graph);\n \t\tpair_chunk(cf, GRAPH_CHUNKID_GENERATION_DATA_OVERFLOW,\n@@ -462,7 +463,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t\t\tgraph->read_generation_data = 1;\n \t}\n \n-\tif (s->commit_graph_changed_paths_version) {\n+\tif (r->settings.commit_graph_changed_paths_version) {\n \t\tread_chunk(cf, GRAPH_CHUNKID_BLOOMINDEXES,\n \t\t\t   graph_read_bloom_index, graph);\n \t\tread_chunk(cf, GRAPH_CHUNKID_BLOOMDATA,\n@@ -479,7 +480,7 @@ struct commit_graph *parse_commit_graph(struct repo_settings *s,\n \t}\n \n \toidread(&graph->oid, graph->data + graph->data_len - graph->hash_algo->rawsz,\n-\t\tthe_repository->hash_algo);\n+\t\tr->hash_algo);\n \n \tfree_chunkfile(cf);\n \treturn graph;\ndiff --git a/commit-graph.h b/commit-graph.h\nindex 7dc1f2b22bd..7bbc69989ce 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -128,7 +128,7 @@ struct repo_settings;\n  * Callers should initialize the repo_settings with prepare_repo_settings()\n  * prior to calling parse_commit_graph().\n  */\n-struct commit_graph *parse_commit_graph(struct repo_settings *s,\n+struct commit_graph *parse_commit_graph(struct repository *r,\n \t\t\t\t\tvoid *graph_map, size_t graph_size);\n \n /*\ndiff --git a/oss-fuzz/fuzz-commit-graph.c b/oss-fuzz/fuzz-commit-graph.c\nindex fbb77fec197..fb8b8787a46 100644\n--- a/oss-fuzz/fuzz-commit-graph.c\n+++ b/oss-fuzz/fuzz-commit-graph.c\n@@ -4,9 +4,6 @@\n #include \"commit-graph.h\"\n #include \"repository.h\"\n \n-struct commit_graph *parse_commit_graph(struct repo_settings *s,\n-\t\t\t\t\tvoid *graph_map, size_t graph_size);\n-\n int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);\n \n int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n@@ -22,9 +19,10 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)\n \t * possible.\n \t */\n \trepo_set_hash_algo(the_repository, GIT_HASH_SHA1);\n+\tthe_repository->settings.initialized = 1;\n \tthe_repository->settings.commit_graph_generation_version = 2;\n \tthe_repository->settings.commit_graph_changed_paths_version = 1;\n-\tg = parse_commit_graph(&the_repository->settings, (void *)data, size);\n+\tg = parse_commit_graph(the_repository, (void *)data, size);\n \trepo_clear(the_repository);\n \tfree_commit_graph(g);\n \n\n-- \n2.51.0.rc1.215.g0f929dcec7.dirty\n\n"},{"id":"524233","messageId":"20250815-b4-pks-commit-graph-wo-the-repository-v4-4-b6b651178cce@pks.im","threadId":"63902","inReplyTo":"20250815-b4-pks-commit-graph-wo-the-repository-v4-0-b6b651178cce@pks.im","subject":"[PATCH v4 4/6] commit-graph: stop using `the_hash_algo`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-15T05:49:50Z","receivedAt":"2025-08-15T05:50:05Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Stop using `the_hash_algo` as it implicitly relies on `the_repository`.\nInstead, we either use the hash algo provided via the context or, if\nthere is no such hash algo, we use `the_repository` explicitly. Such\nuses will be removed in subsequent commits.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit-graph.c |  3 ++-\n commit-graph.c         | 27 ++++++++++++++-------------\n commit-graph.h         |  3 ++-\n 3 files changed, 18 insertions(+), 15 deletions(-)\n\ndiff --git a/builtin/commit-graph.c b/builtin/commit-graph.c\nindex 25018a0b9d..fa6dd34d8d 100644\n--- a/builtin/commit-graph.c\n+++ b/builtin/commit-graph.c\n@@ -108,7 +108,8 @@ static int graph_verify(int argc, const char **argv, const char *prefix,\n \t\topened = OPENED_GRAPH;\n \telse if (errno != ENOENT)\n \t\tdie_errno(_(\"Could not open commit-graph '%s'\"), graph_name);\n-\telse if (open_commit_graph_chain(chain_name, &fd, &st))\n+\telse if (open_commit_graph_chain(chain_name, &fd, &st,\n+\t\t\t\t\t the_repository->hash_algo))\n \t\topened = OPENED_CHAIN;\n \telse if (errno != ENOENT)\n \t\tdie_errno(_(\"could not open commit-graph chain '%s'\"), chain_name);\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 2f314a7407..46f55c8bb4 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -264,7 +264,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \n \tgraph_size = xsize_t(st->st_size);\n \n-\tif (graph_size < graph_min_size(the_hash_algo)) {\n+\tif (graph_size < graph_min_size(r->hash_algo)) {\n \t\tclose(fd);\n \t\terror(_(\"commit-graph file is too small\"));\n \t\treturn NULL;\n@@ -319,7 +319,7 @@ static int graph_read_commit_data(const unsigned char *chunk_start,\n \t\t\t\t  size_t chunk_size, void *data)\n {\n \tstruct commit_graph *g = data;\n-\tif (chunk_size / graph_data_width(the_hash_algo) != g->num_commits)\n+\tif (chunk_size / graph_data_width(g->hash_algo) != g->num_commits)\n \t\treturn error(_(\"commit-graph commit data chunk is wrong size\"));\n \tg->chunk_commit_data = chunk_start;\n \treturn 0;\n@@ -620,7 +620,8 @@ static int add_graph_to_chain(struct commit_graph *g,\n }\n \n int open_commit_graph_chain(const char *chain_file,\n-\t\t\t    int *fd, struct stat *st)\n+\t\t\t    int *fd, struct stat *st,\n+\t\t\t    const struct git_hash_algo *hash_algo)\n {\n \t*fd = git_open(chain_file);\n \tif (*fd < 0)\n@@ -629,7 +630,7 @@ int open_commit_graph_chain(const char *chain_file,\n \t\tclose(*fd);\n \t\treturn 0;\n \t}\n-\tif (st->st_size < the_hash_algo->hexsz) {\n+\tif (st->st_size < hash_algo->hexsz) {\n \t\tclose(*fd);\n \t\tif (!st->st_size) {\n \t\t\t/* treat empty files the same as missing */\n@@ -653,7 +654,7 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \tint i = 0, valid = 1, count;\n \tFILE *fp = xfdopen(fd, \"r\");\n \n-\tcount = st->st_size / (the_hash_algo->hexsz + 1);\n+\tcount = st->st_size / (r->hash_algo->hexsz + 1);\n \tCALLOC_ARRAY(oids, count);\n \n \todb_prepare_alternates(r->objects);\n@@ -715,7 +716,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,\n \tint fd;\n \tstruct commit_graph *g = NULL;\n \n-\tif (open_commit_graph_chain(chain_file, &fd, &st)) {\n+\tif (open_commit_graph_chain(chain_file, &fd, &st, r->hash_algo)) {\n \t\tint incomplete;\n \t\t/* ownership of fd is taken over by load function */\n \t\tg = load_commit_graph_chain_fd_st(r, fd, &st, &incomplete);\n@@ -907,7 +908,7 @@ static void fill_commit_graph_info(struct commit *item, struct commit_graph *g,\n \t\tdie(_(\"invalid commit position. commit-graph is likely corrupt\"));\n \n \tlex_index = pos - g->num_commits_in_base;\n-\tcommit_data = g->chunk_commit_data + st_mult(graph_data_width(the_hash_algo), lex_index);\n+\tcommit_data = g->chunk_commit_data + st_mult(graph_data_width(g->hash_algo), lex_index);\n \n \tgraph_data = commit_graph_data_at(item);\n \tgraph_data->graph_pos = pos;\n@@ -1111,7 +1112,7 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\tg = g->base_graph;\n \n \tcommit_data = g->chunk_commit_data +\n-\t\t\tst_mult(graph_data_width(the_hash_algo),\n+\t\t\tst_mult(graph_data_width(g->hash_algo),\n \t\t\t\tgraph_pos - g->num_commits_in_base);\n \n \toidread(&oid, commit_data, the_repository->hash_algo);\n@@ -1220,7 +1221,7 @@ static int write_graph_chunk_oids(struct hashfile *f,\n \tint count;\n \tfor (count = 0; count < ctx->commits.nr; count++, list++) {\n \t\tdisplay_progress(ctx->progress, ++ctx->progress_cnt);\n-\t\thashwrite(f, (*list)->object.oid.hash, the_hash_algo->rawsz);\n+\t\thashwrite(f, (*list)->object.oid.hash, f->algop->rawsz);\n \t}\n \n \treturn 0;\n@@ -1251,7 +1252,7 @@ static int write_graph_chunk_data(struct hashfile *f,\n \t\t\tdie(_(\"unable to parse commit %s\"),\n \t\t\t\toid_to_hex(&(*list)->object.oid));\n \t\ttree = get_commit_tree_oid(*list);\n-\t\thashwrite(f, tree->hash, the_hash_algo->rawsz);\n+\t\thashwrite(f, tree->hash, ctx->r->hash_algo->rawsz);\n \n \t\tparent = (*list)->parents;\n \n@@ -2034,7 +2035,7 @@ static int write_graph_chunk_base_1(struct hashfile *f,\n \t\treturn 0;\n \n \tnum = write_graph_chunk_base_1(f, g->base_graph);\n-\thashwrite(f, g->oid.hash, the_hash_algo->rawsz);\n+\thashwrite(f, g->oid.hash, g->hash_algo->rawsz);\n \treturn num + 1;\n }\n \n@@ -2058,7 +2059,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \tstruct hashfile *f;\n \tstruct tempfile *graph_layer; /* when ctx->split is non-zero */\n \tstruct lock_file lk = LOCK_INIT;\n-\tconst unsigned hashsz = the_hash_algo->rawsz;\n+\tconst unsigned hashsz = ctx->r->hash_algo->rawsz;\n \tstruct strbuf progress_title = STRBUF_INIT;\n \tstruct chunkfile *cf;\n \tunsigned char file_hash[GIT_MAX_RAWSZ];\n@@ -2146,7 +2147,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \thashwrite_be32(f, GRAPH_SIGNATURE);\n \n \thashwrite_u8(f, GRAPH_VERSION);\n-\thashwrite_u8(f, oid_version(the_hash_algo));\n+\thashwrite_u8(f, oid_version(ctx->r->hash_algo));\n \thashwrite_u8(f, get_num_chunks(cf));\n \thashwrite_u8(f, ctx->num_commit_graphs_after - 1);\n \ndiff --git a/commit-graph.h b/commit-graph.h\nindex 7bbc69989c..df10daf01c 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -32,7 +32,8 @@ struct string_list;\n char *get_commit_graph_filename(struct odb_source *source);\n char *get_commit_graph_chain_filename(struct odb_source *source);\n int open_commit_graph(const char *graph_file, int *fd, struct stat *st);\n-int open_commit_graph_chain(const char *chain_file, int *fd, struct stat *st);\n+int open_commit_graph_chain(const char *chain_file, int *fd, struct stat *st,\n+\t\t\t    const struct git_hash_algo *hash_algo);\n \n /*\n  * Given a commit struct, try to fill the commit struct info, including:\n\n-- \n2.51.0.rc1.215.g0f929dcec7.dirty\n\n"},{"id":"524234","messageId":"20250815-b4-pks-commit-graph-wo-the-repository-v4-5-b6b651178cce@pks.im","threadId":"63902","inReplyTo":"20250815-b4-pks-commit-graph-wo-the-repository-v4-0-b6b651178cce@pks.im","subject":"[PATCH v4 5/6] commit-graph: stop using `the_repository`","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-15T05:49:51Z","receivedAt":"2025-08-15T05:50:08Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"There's still a bunch of uses of `the_repository` in \"commit-graph.c\",\nwhich we want to stop using due to it being a global variable. Refactor\nthe code to stop using `the_repository` in favor of the repository\nprovided via the calling context.\n\nThis allows us to drop the `USE_THE_REPOSITORY_VARIABLE` macro.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit.c |  2 +-\n builtin/merge.c  |  2 +-\n commit-graph.c   | 76 +++++++++++++++++++++++++++++---------------------------\n commit-graph.h   |  2 +-\n 4 files changed, 42 insertions(+), 40 deletions(-)\n\ndiff --git a/builtin/commit.c b/builtin/commit.c\nindex 63e7158e98..8ca0aede48 100644\n--- a/builtin/commit.c\n+++ b/builtin/commit.c\n@@ -1933,7 +1933,7 @@ int cmd_commit(int argc,\n \t\t      \"new index file. Check that disk is not full and quota is\\n\"\n \t\t      \"not exceeded, and then \\\"git restore --staged :/\\\" to recover.\"));\n \n-\tgit_test_write_commit_graph_or_die();\n+\tgit_test_write_commit_graph_or_die(the_repository->objects->sources);\n \n \trepo_rerere(the_repository, 0);\n \trun_auto_maintenance(quiet);\ndiff --git a/builtin/merge.c b/builtin/merge.c\nindex 18b22c0a26..263cb58471 100644\n--- a/builtin/merge.c\n+++ b/builtin/merge.c\n@@ -1862,7 +1862,7 @@ int cmd_merge(int argc,\n \tif (squash) {\n \t\tfinish(head_commit, remoteheads, NULL, NULL);\n \n-\t\tgit_test_write_commit_graph_or_die();\n+\t\tgit_test_write_commit_graph_or_die(the_repository->objects->sources);\n \t} else\n \t\twrite_merge_state(remoteheads);\n \ndiff --git a/commit-graph.c b/commit-graph.c\nindex 46f55c8bb4..180b826239 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -1,4 +1,3 @@\n-#define USE_THE_REPOSITORY_VARIABLE\n #define DISABLE_SIGN_COMPARE_WARNINGS\n \n #include \"git-compat-util.h\"\n@@ -28,7 +27,7 @@\n #include \"tree.h\"\n #include \"chunk-format.h\"\n \n-void git_test_write_commit_graph_or_die(void)\n+void git_test_write_commit_graph_or_die(struct odb_source *source)\n {\n \tint flags = 0;\n \tif (!git_env_bool(GIT_TEST_COMMIT_GRAPH, 0))\n@@ -37,8 +36,7 @@ void git_test_write_commit_graph_or_die(void)\n \tif (git_env_bool(GIT_TEST_COMMIT_GRAPH_CHANGED_PATHS, 0))\n \t\tflags = COMMIT_GRAPH_WRITE_BLOOM_FILTERS;\n \n-\tif (write_commit_graph_reachable(the_repository->objects->sources,\n-\t\t\t\t\t flags, NULL))\n+\tif (write_commit_graph_reachable(source, flags, NULL))\n \t\tdie(\"failed to write commit-graph under GIT_TEST_COMMIT_GRAPH\");\n }\n \n@@ -596,7 +594,7 @@ static int add_graph_to_chain(struct commit_graph *g,\n \t\tif (!cur_g ||\n \t\t    !oideq(&oids[n], &cur_g->oid) ||\n \t\t    !hasheq(oids[n].hash, g->chunk_base_graphs + st_mult(g->hash_algo->rawsz, n),\n-\t\t\t    the_repository->hash_algo)) {\n+\t\t\t    g->hash_algo)) {\n \t\t\twarning(_(\"commit-graph chain does not match\"));\n \t\t\treturn 0;\n \t\t}\n@@ -665,7 +663,7 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \t\tif (strbuf_getline_lf(&line, fp) == EOF)\n \t\t\tbreak;\n \n-\t\tif (get_oid_hex(line.buf, &oids[i])) {\n+\t\tif (get_oid_hex_algop(line.buf, &oids[i], r->hash_algo)) {\n \t\t\twarning(_(\"invalid commit-graph chain: line '%s' not a hash\"),\n \t\t\t\tline.buf);\n \t\t\tvalid = 0;\n@@ -751,7 +749,7 @@ static void prepare_commit_graph_one(struct repository *r,\n  * Return 1 if commit_graph is non-NULL, and 0 otherwise.\n  *\n  * On the first invocation, this function attempts to load the commit\n- * graph if the_repository is configured to have one.\n+ * graph if the repository is configured to have one.\n  */\n static int prepare_commit_graph(struct repository *r)\n {\n@@ -872,7 +870,7 @@ static void load_oid_from_graph(struct commit_graph *g,\n \tlex_index = pos - g->num_commits_in_base;\n \n \toidread(oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, lex_index),\n-\t\tthe_repository->hash_algo);\n+\t\tg->hash_algo);\n }\n \n static struct commit_list **insert_parent_or_die(struct repository *r,\n@@ -1115,7 +1113,7 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\t\tst_mult(graph_data_width(g->hash_algo),\n \t\t\t\tgraph_pos - g->num_commits_in_base);\n \n-\toidread(&oid, commit_data, the_repository->hash_algo);\n+\toidread(&oid, commit_data, g->hash_algo);\n \tset_commit_tree(c, lookup_tree(r, &oid));\n \n \treturn c->maybe_tree;\n@@ -1542,7 +1540,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Loading known commits in commit graph\"),\n \t\t\t\t\tctx->oids.nr);\n \tfor (i = 0; i < ctx->oids.nr; i++) {\n@@ -1560,7 +1558,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)\n \t */\n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Expanding reachable commits in commit graph\"),\n \t\t\t\t\t0);\n \tfor (i = 0; i < ctx->oids.nr; i++) {\n@@ -1581,7 +1579,7 @@ static void close_reachable(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Clearing commit marks in commit graph\"),\n \t\t\t\t\tctx->oids.nr);\n \tfor (i = 0; i < ctx->oids.nr; i++) {\n@@ -1699,7 +1697,7 @@ static void compute_topological_levels(struct write_commit_graph_context *ctx)\n \tif (ctx->report_progress)\n \t\tinfo.progress = ctx->progress\n \t\t\t      = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Computing commit graph topological levels\"),\n \t\t\t\t\tctx->commits.nr);\n \n@@ -1734,7 +1732,7 @@ static void compute_generation_numbers(struct write_commit_graph_context *ctx)\n \tif (ctx->report_progress)\n \t\tinfo.progress = ctx->progress\n \t\t\t      = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Computing commit graph generation numbers\"),\n \t\t\t\t\tctx->commits.nr);\n \n@@ -1811,7 +1809,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tprogress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\t_(\"Computing commit changed paths Bloom filters\"),\n \t\t\tctx->commits.nr);\n \n@@ -1857,6 +1855,7 @@ static void compute_bloom_filters(struct write_commit_graph_context *ctx)\n }\n \n struct refs_cb_data {\n+\tstruct repository *repo;\n \tstruct oidset *commits;\n \tstruct progress *progress;\n };\n@@ -1869,9 +1868,9 @@ static int add_ref_to_set(const char *refname UNUSED,\n \tstruct object_id peeled;\n \tstruct refs_cb_data *data = (struct refs_cb_data *)cb_data;\n \n-\tif (!peel_iterated_oid(the_repository, oid, &peeled))\n+\tif (!peel_iterated_oid(data->repo, oid, &peeled))\n \t\toid = &peeled;\n-\tif (odb_read_object_info(the_repository->objects, oid, NULL) == OBJ_COMMIT)\n+\tif (odb_read_object_info(data->repo->objects, oid, NULL) == OBJ_COMMIT)\n \t\toidset_insert(data->commits, oid);\n \n \tdisplay_progress(data->progress, oidset_size(data->commits));\n@@ -1888,13 +1887,15 @@ int write_commit_graph_reachable(struct odb_source *source,\n \tint result;\n \n \tmemset(&data, 0, sizeof(data));\n+\tdata.repo = source->odb->repo;\n \tdata.commits = &commits;\n+\n \tif (flags & COMMIT_GRAPH_WRITE_PROGRESS)\n \t\tdata.progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tsource->odb->repo,\n \t\t\t_(\"Collecting referenced commits\"), 0);\n \n-\trefs_for_each_ref(get_main_ref_store(the_repository), add_ref_to_set,\n+\trefs_for_each_ref(get_main_ref_store(source->odb->repo), add_ref_to_set,\n \t\t\t  &data);\n \n \tstop_progress(&data.progress);\n@@ -1923,7 +1924,7 @@ static int fill_oids_from_packs(struct write_commit_graph_context *ctx,\n \t\t\t       \"Finding commits for commit graph in %\"PRIuMAX\" packs\",\n \t\t\t       pack_indexes->nr),\n \t\t\t    (uintmax_t)pack_indexes->nr);\n-\t\tctx->progress = start_delayed_progress(the_repository,\n+\t\tctx->progress = start_delayed_progress(ctx->r,\n \t\t\t\t\t\t       progress_title.buf, 0);\n \t\tctx->progress_done = 0;\n \t}\n@@ -1977,7 +1978,7 @@ static void fill_oids_from_all_packs(struct write_commit_graph_context *ctx)\n {\n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\t_(\"Finding commits for commit graph among packed objects\"),\n \t\t\tctx->approx_nr_objects);\n \tfor_each_packed_object(ctx->r, add_packed_commits, ctx,\n@@ -1996,7 +1997,7 @@ static void copy_oids_to_commits(struct write_commit_graph_context *ctx)\n \tctx->num_extra_edges = 0;\n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\t_(\"Finding extra edges in commit graph\"),\n \t\t\tctx->oids.nr);\n \toid_array_sort(&ctx->oids);\n@@ -2075,7 +2076,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\tctx->graph_name = get_commit_graph_filename(ctx->odb_source);\n \t}\n \n-\tif (safe_create_leading_directories(the_repository, ctx->graph_name)) {\n+\tif (safe_create_leading_directories(ctx->r, ctx->graph_name)) {\n \t\terror(_(\"unable to create leading directories of %s\"),\n \t\t\tctx->graph_name);\n \t\treturn -1;\n@@ -2094,18 +2095,18 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\t\treturn -1;\n \t\t}\n \n-\t\tif (adjust_shared_perm(the_repository, get_tempfile_path(graph_layer))) {\n+\t\tif (adjust_shared_perm(ctx->r, get_tempfile_path(graph_layer))) {\n \t\t\terror(_(\"unable to adjust shared permissions for '%s'\"),\n \t\t\t      get_tempfile_path(graph_layer));\n \t\t\treturn -1;\n \t\t}\n \n-\t\tf = hashfd(the_repository->hash_algo,\n+\t\tf = hashfd(ctx->r->hash_algo,\n \t\t\t   get_tempfile_fd(graph_layer), get_tempfile_path(graph_layer));\n \t} else {\n \t\thold_lock_file_for_update_mode(&lk, ctx->graph_name,\n \t\t\t\t\t       LOCK_DIE_ON_ERROR, 0444);\n-\t\tf = hashfd(the_repository->hash_algo,\n+\t\tf = hashfd(ctx->r->hash_algo,\n \t\t\t   get_lock_file_fd(&lk), get_lock_file_path(&lk));\n \t}\n \n@@ -2158,7 +2159,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\t\t       get_num_chunks(cf)),\n \t\t\t    get_num_chunks(cf));\n \t\tctx->progress = start_delayed_progress(\n-\t\t\tthe_repository,\n+\t\t\tctx->r,\n \t\t\tprogress_title.buf,\n \t\t\tst_mult(get_num_chunks(cf), ctx->commits.nr));\n \t}\n@@ -2216,7 +2217,8 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)\n \t\t}\n \n \t\tfree(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);\n-\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(hash_to_hex(file_hash));\n+\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] =\n+\t\t\txstrdup(hash_to_hex_algop(file_hash, ctx->r->hash_algo));\n \t\tfinal_graph_name = get_split_graph_filename(ctx->odb_source,\n \t\t\t\t\tctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);\n \t\tfree(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1]);\n@@ -2371,7 +2373,7 @@ static void sort_and_scan_merged_commits(struct write_commit_graph_context *ctx)\n \n \tif (ctx->report_progress)\n \t\tctx->progress = start_delayed_progress(\n-\t\t\t\t\tthe_repository,\n+\t\t\t\t\tctx->r,\n \t\t\t\t\t_(\"Scanning merged commits\"),\n \t\t\t\t\tctx->commits.nr);\n \n@@ -2416,7 +2418,7 @@ static void merge_commit_graphs(struct write_commit_graph_context *ctx)\n \t\tcurrent_graph_number--;\n \n \t\tif (ctx->report_progress)\n-\t\t\tctx->progress = start_delayed_progress(the_repository,\n+\t\t\tctx->progress = start_delayed_progress(ctx->r,\n \t\t\t\t\t\t\t       _(\"Merging commit-graph\"), 0);\n \n \t\tmerge_commit_graph(ctx, g);\n@@ -2519,7 +2521,7 @@ int write_commit_graph(struct odb_source *source,\n \t\t       enum commit_graph_write_flags flags,\n \t\t       const struct commit_graph_opts *opts)\n {\n-\tstruct repository *r = the_repository;\n+\tstruct repository *r = source->odb->repo;\n \tstruct write_commit_graph_context ctx = {\n \t\t.r = r,\n \t\t.odb_source = source,\n@@ -2619,14 +2621,14 @@ int write_commit_graph(struct odb_source *source,\n \t\t\treplace = ctx.opts->split_flags & COMMIT_GRAPH_SPLIT_REPLACE;\n \t}\n \n-\tctx.approx_nr_objects = repo_approximate_object_count(the_repository);\n+\tctx.approx_nr_objects = repo_approximate_object_count(r);\n \n \tif (ctx.append && ctx.r->objects->commit_graph) {\n \t\tstruct commit_graph *g = ctx.r->objects->commit_graph;\n \t\tfor (i = 0; i < g->num_commits; i++) {\n \t\t\tstruct object_id oid;\n \t\t\toidread(&oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n-\t\t\t\tthe_repository->hash_algo);\n+\t\t\t\tr->hash_algo);\n \t\t\toid_array_append(&ctx.oids, &oid);\n \t\t}\n \t}\n@@ -2734,7 +2736,7 @@ static void graph_report(const char *fmt, ...)\n \n static int commit_graph_checksum_valid(struct commit_graph *g)\n {\n-\treturn hashfile_checksum_valid(the_repository->hash_algo,\n+\treturn hashfile_checksum_valid(g->hash_algo,\n \t\t\t\t       g->data, g->data_len);\n }\n \n@@ -2757,7 +2759,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\tstruct commit *graph_commit;\n \n \t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n-\t\t\tthe_repository->hash_algo);\n+\t\t\tg->hash_algo);\n \n \t\tif (i && oidcmp(&prev_oid, &cur_oid) >= 0)\n \t\t\tgraph_report(_(\"commit-graph has incorrect OID order: %s then %s\"),\n@@ -2802,7 +2804,7 @@ static int verify_one_commit_graph(struct repository *r,\n \n \t\tdisplay_progress(progress, ++(*seen));\n \t\toidread(&cur_oid, g->chunk_oid_lookup + st_mult(g->hash_algo->rawsz, i),\n-\t\t\tthe_repository->hash_algo);\n+\t\t\tg->hash_algo);\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\n \t\todb_commit = (struct commit *)create_object(r, &cur_oid, alloc_commit_node(r));\n@@ -2906,7 +2908,7 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n \t\tif (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW))\n \t\t\ttotal += g->num_commits_in_base;\n \n-\t\tprogress = start_progress(the_repository,\n+\t\tprogress = start_progress(r,\n \t\t\t\t\t  _(\"Verifying commits in commit graph\"),\n \t\t\t\t\t  total);\n \t}\ndiff --git a/commit-graph.h b/commit-graph.h\nindex df10daf01c..0a67ac9280 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -21,7 +21,7 @@\n  * call this method oustide of a builtin, and only if you know what\n  * you are doing!\n  */\n-void git_test_write_commit_graph_or_die(void);\n+void git_test_write_commit_graph_or_die(struct odb_source *source);\n \n struct commit;\n struct bloom_filter_settings;\n\n-- \n2.51.0.rc1.215.g0f929dcec7.dirty\n\n"},{"id":"524235","messageId":"20250815-b4-pks-commit-graph-wo-the-repository-v4-6-b6b651178cce@pks.im","threadId":"63902","inReplyTo":"20250815-b4-pks-commit-graph-wo-the-repository-v4-0-b6b651178cce@pks.im","subject":"[PATCH v4 6/6] commit-graph: stop passing in redundant repository","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-08-15T05:49:52Z","receivedAt":"2025-08-15T05:50:12Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"Many of the commit-graph related functions take in both a repository and\nthe object database source (directly or via `struct commit_graph`) for\nwhich we are supposed to load such a commit-graph. In the best case this\ninformation is simply redundant as the source already contains a\nreference to its owning object database, which in turn has a reference\nto its repository. In the worst case this information could even\nmismatch when passing in a source that doesn't belong to the same\nrepository.\n\nRefactor the code so that we only pass in the object database source in\nthose cases.\n\nThere is one exception though, namely `load_commit_graph_chain_fd_st()`,\nwhich is responsible for loading a commit-graph chain. It is expected\nthat parts of the commit-graph chain aren't located in the same object\nsource as the chain file itself, but in a different one. Consequently,\nthis function doesn't work on the source level but on the database level\ninstead.\n\nSigned-off-by: Patrick Steinhardt <ps@pks.im>\n---\n builtin/commit-graph.c     |   6 +--\n commit-graph.c             | 120 +++++++++++++++++++--------------------------\n commit-graph.h             |  12 ++---\n t/helper/test-read-graph.c |   2 +-\n 4 files changed, 59 insertions(+), 81 deletions(-)\n\ndiff --git a/builtin/commit-graph.c b/builtin/commit-graph.c\nindex fa6dd34d8d..dbeaeeaed3 100644\n--- a/builtin/commit-graph.c\n+++ b/builtin/commit-graph.c\n@@ -121,15 +121,15 @@ static int graph_verify(int argc, const char **argv, const char *prefix,\n \tif (opened == OPENED_NONE)\n \t\treturn 0;\n \telse if (opened == OPENED_GRAPH)\n-\t\tgraph = load_commit_graph_one_fd_st(the_repository, fd, &st, source);\n+\t\tgraph = load_commit_graph_one_fd_st(source, fd, &st);\n \telse\n-\t\tgraph = load_commit_graph_chain_fd_st(the_repository, fd, &st,\n+\t\tgraph = load_commit_graph_chain_fd_st(the_repository->objects, fd, &st,\n \t\t\t\t\t\t      &incomplete_chain);\n \n \tif (!graph)\n \t\treturn 1;\n \n-\tret = verify_commit_graph(the_repository, graph, flags);\n+\tret = verify_commit_graph(graph, flags);\n \tfree_commit_graph(graph);\n \n \tif (incomplete_chain) {\ndiff --git a/commit-graph.c b/commit-graph.c\nindex 180b826239..5aaaa9715a 100644\n--- a/commit-graph.c\n+++ b/commit-graph.c\n@@ -252,9 +252,8 @@ int open_commit_graph(const char *graph_file, int *fd, struct stat *st)\n \treturn 1;\n }\n \n-struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n-\t\t\t\t\t\t int fd, struct stat *st,\n-\t\t\t\t\t\t struct odb_source *source)\n+struct commit_graph *load_commit_graph_one_fd_st(struct odb_source *source,\n+\t\t\t\t\t\t int fd, struct stat *st)\n {\n \tvoid *graph_map;\n \tsize_t graph_size;\n@@ -262,7 +261,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \n \tgraph_size = xsize_t(st->st_size);\n \n-\tif (graph_size < graph_min_size(r->hash_algo)) {\n+\tif (graph_size < graph_min_size(source->odb->repo->hash_algo)) {\n \t\tclose(fd);\n \t\terror(_(\"commit-graph file is too small\"));\n \t\treturn NULL;\n@@ -270,7 +269,7 @@ struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n \tgraph_map = xmmap(NULL, graph_size, PROT_READ, MAP_PRIVATE, fd, 0);\n \tclose(fd);\n \n-\tret = parse_commit_graph(r, graph_map, graph_size);\n+\tret = parse_commit_graph(source->odb->repo, graph_map, graph_size);\n \tif (ret)\n \t\tret->odb_source = source;\n \telse\n@@ -490,11 +489,9 @@ struct commit_graph *parse_commit_graph(struct repository *r,\n \treturn NULL;\n }\n \n-static struct commit_graph *load_commit_graph_one(struct repository *r,\n-\t\t\t\t\t\t  const char *graph_file,\n-\t\t\t\t\t\t  struct odb_source *source)\n+static struct commit_graph *load_commit_graph_one(struct odb_source *source,\n+\t\t\t\t\t\t  const char *graph_file)\n {\n-\n \tstruct stat st;\n \tint fd;\n \tstruct commit_graph *g;\n@@ -503,19 +500,17 @@ static struct commit_graph *load_commit_graph_one(struct repository *r,\n \tif (!open_ok)\n \t\treturn NULL;\n \n-\tg = load_commit_graph_one_fd_st(r, fd, &st, source);\n-\n+\tg = load_commit_graph_one_fd_st(source, fd, &st);\n \tif (g)\n \t\tg->filename = xstrdup(graph_file);\n \n \treturn g;\n }\n \n-static struct commit_graph *load_commit_graph_v1(struct repository *r,\n-\t\t\t\t\t\t struct odb_source *source)\n+static struct commit_graph *load_commit_graph_v1(struct odb_source *source)\n {\n \tchar *graph_name = get_commit_graph_filename(source);\n-\tstruct commit_graph *g = load_commit_graph_one(r, graph_name, source);\n+\tstruct commit_graph *g = load_commit_graph_one(source, graph_name);\n \tfree(graph_name);\n \n \treturn g;\n@@ -642,7 +637,7 @@ int open_commit_graph_chain(const char *chain_file,\n \treturn 1;\n }\n \n-struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n+struct commit_graph *load_commit_graph_chain_fd_st(struct object_database *odb,\n \t\t\t\t\t\t   int fd, struct stat *st,\n \t\t\t\t\t\t   int *incomplete_chain)\n {\n@@ -652,10 +647,10 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \tint i = 0, valid = 1, count;\n \tFILE *fp = xfdopen(fd, \"r\");\n \n-\tcount = st->st_size / (r->hash_algo->hexsz + 1);\n+\tcount = st->st_size / (odb->repo->hash_algo->hexsz + 1);\n \tCALLOC_ARRAY(oids, count);\n \n-\todb_prepare_alternates(r->objects);\n+\todb_prepare_alternates(odb);\n \n \tfor (i = 0; i < count; i++) {\n \t\tstruct odb_source *source;\n@@ -663,7 +658,7 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \t\tif (strbuf_getline_lf(&line, fp) == EOF)\n \t\t\tbreak;\n \n-\t\tif (get_oid_hex_algop(line.buf, &oids[i], r->hash_algo)) {\n+\t\tif (get_oid_hex_algop(line.buf, &oids[i], odb->repo->hash_algo)) {\n \t\t\twarning(_(\"invalid commit-graph chain: line '%s' not a hash\"),\n \t\t\t\tline.buf);\n \t\t\tvalid = 0;\n@@ -671,9 +666,9 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \t\t}\n \n \t\tvalid = 0;\n-\t\tfor (source = r->objects->sources; source; source = source->next) {\n+\t\tfor (source = odb->sources; source; source = source->next) {\n \t\t\tchar *graph_name = get_split_graph_filename(source, line.buf);\n-\t\t\tstruct commit_graph *g = load_commit_graph_one(r, graph_name, source);\n+\t\t\tstruct commit_graph *g = load_commit_graph_one(source, graph_name);\n \n \t\t\tfree(graph_name);\n \n@@ -706,45 +701,33 @@ struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n \treturn graph_chain;\n }\n \n-static struct commit_graph *load_commit_graph_chain(struct repository *r,\n-\t\t\t\t\t\t    struct odb_source *source)\n+static struct commit_graph *load_commit_graph_chain(struct odb_source *source)\n {\n \tchar *chain_file = get_commit_graph_chain_filename(source);\n \tstruct stat st;\n \tint fd;\n \tstruct commit_graph *g = NULL;\n \n-\tif (open_commit_graph_chain(chain_file, &fd, &st, r->hash_algo)) {\n+\tif (open_commit_graph_chain(chain_file, &fd, &st, source->odb->repo->hash_algo)) {\n \t\tint incomplete;\n \t\t/* ownership of fd is taken over by load function */\n-\t\tg = load_commit_graph_chain_fd_st(r, fd, &st, &incomplete);\n+\t\tg = load_commit_graph_chain_fd_st(source->odb, fd, &st, &incomplete);\n \t}\n \n \tfree(chain_file);\n \treturn g;\n }\n \n-struct commit_graph *read_commit_graph_one(struct repository *r,\n-\t\t\t\t\t   struct odb_source *source)\n+struct commit_graph *read_commit_graph_one(struct odb_source *source)\n {\n-\tstruct commit_graph *g = load_commit_graph_v1(r, source);\n+\tstruct commit_graph *g = load_commit_graph_v1(source);\n \n \tif (!g)\n-\t\tg = load_commit_graph_chain(r, source);\n+\t\tg = load_commit_graph_chain(source);\n \n \treturn g;\n }\n \n-static void prepare_commit_graph_one(struct repository *r,\n-\t\t\t\t     struct odb_source *source)\n-{\n-\n-\tif (r->objects->commit_graph)\n-\t\treturn;\n-\n-\tr->objects->commit_graph = read_commit_graph_one(r, source);\n-}\n-\n /*\n  * Return 1 if commit_graph is non-NULL, and 0 otherwise.\n  *\n@@ -785,10 +768,12 @@ static int prepare_commit_graph(struct repository *r)\n \t\treturn 0;\n \n \todb_prepare_alternates(r->objects);\n-\tfor (source = r->objects->sources;\n-\t     !r->objects->commit_graph && source;\n-\t     source = source->next)\n-\t\tprepare_commit_graph_one(r, source);\n+\tfor (source = r->objects->sources; source; source = source->next) {\n+\t\tr->objects->commit_graph = read_commit_graph_one(source);\n+\t\tif (r->objects->commit_graph)\n+\t\t\tbreak;\n+\t}\n+\n \treturn !!r->objects->commit_graph;\n }\n \n@@ -873,8 +858,7 @@ static void load_oid_from_graph(struct commit_graph *g,\n \t\tg->hash_algo);\n }\n \n-static struct commit_list **insert_parent_or_die(struct repository *r,\n-\t\t\t\t\t\t struct commit_graph *g,\n+static struct commit_list **insert_parent_or_die(struct commit_graph *g,\n \t\t\t\t\t\t uint32_t pos,\n \t\t\t\t\t\t struct commit_list **pptr)\n {\n@@ -885,7 +869,7 @@ static struct commit_list **insert_parent_or_die(struct repository *r,\n \t\tdie(\"invalid parent position %\"PRIu32, pos);\n \n \tload_oid_from_graph(g, pos, &oid);\n-\tc = lookup_commit(r, &oid);\n+\tc = lookup_commit(g->odb_source->odb->repo, &oid);\n \tif (!c)\n \t\tdie(_(\"could not find commit %s\"), oid_to_hex(&oid));\n \tcommit_graph_data_at(c)->graph_pos = pos;\n@@ -941,8 +925,7 @@ static inline void set_commit_tree(struct commit *c, struct tree *t)\n \tc->maybe_tree = t;\n }\n \n-static int fill_commit_in_graph(struct repository *r,\n-\t\t\t\tstruct commit *item,\n+static int fill_commit_in_graph(struct commit *item,\n \t\t\t\tstruct commit_graph *g, uint32_t pos)\n {\n \tuint32_t edge_value;\n@@ -968,13 +951,13 @@ static int fill_commit_in_graph(struct repository *r,\n \tedge_value = get_be32(commit_data + g->hash_algo->rawsz);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n-\tpptr = insert_parent_or_die(r, g, edge_value, pptr);\n+\tpptr = insert_parent_or_die(g, edge_value, pptr);\n \n \tedge_value = get_be32(commit_data + g->hash_algo->rawsz + 4);\n \tif (edge_value == GRAPH_PARENT_NONE)\n \t\treturn 1;\n \tif (!(edge_value & GRAPH_EXTRA_EDGES_NEEDED)) {\n-\t\tpptr = insert_parent_or_die(r, g, edge_value, pptr);\n+\t\tpptr = insert_parent_or_die(g, edge_value, pptr);\n \t\treturn 1;\n \t}\n \n@@ -989,7 +972,7 @@ static int fill_commit_in_graph(struct repository *r,\n \t\t}\n \t\tedge_value = get_be32(g->chunk_extra_edges +\n \t\t\t\t      sizeof(uint32_t) * parent_data_pos);\n-\t\tpptr = insert_parent_or_die(r, g,\n+\t\tpptr = insert_parent_or_die(g,\n \t\t\t\t\t    edge_value & GRAPH_EDGE_LAST_MASK,\n \t\t\t\t\t    pptr);\n \t\tparent_data_pos++;\n@@ -1055,14 +1038,13 @@ struct commit *lookup_commit_in_graph(struct repository *repo, const struct obje\n \tif (commit->object.parsed)\n \t\treturn commit;\n \n-\tif (!fill_commit_in_graph(repo, commit, repo->objects->commit_graph, pos))\n+\tif (!fill_commit_in_graph(commit, repo->objects->commit_graph, pos))\n \t\treturn NULL;\n \n \treturn commit;\n }\n \n-static int parse_commit_in_graph_one(struct repository *r,\n-\t\t\t\t     struct commit_graph *g,\n+static int parse_commit_in_graph_one(struct commit_graph *g,\n \t\t\t\t     struct commit *item)\n {\n \tuint32_t pos;\n@@ -1071,7 +1053,7 @@ static int parse_commit_in_graph_one(struct repository *r,\n \t\treturn 1;\n \n \tif (find_commit_pos_in_graph(item, g, &pos))\n-\t\treturn fill_commit_in_graph(r, item, g, pos);\n+\t\treturn fill_commit_in_graph(item, g, pos);\n \n \treturn 0;\n }\n@@ -1088,7 +1070,7 @@ int parse_commit_in_graph(struct repository *r, struct commit *item)\n \n \tif (!prepare_commit_graph(r))\n \t\treturn 0;\n-\treturn parse_commit_in_graph_one(r, r->objects->commit_graph, item);\n+\treturn parse_commit_in_graph_one(r->objects->commit_graph, item);\n }\n \n void load_commit_graph_info(struct repository *r, struct commit *item)\n@@ -1098,8 +1080,7 @@ void load_commit_graph_info(struct repository *r, struct commit *item)\n \t\tfill_commit_graph_info(item, r->objects->commit_graph, pos);\n }\n \n-static struct tree *load_tree_for_commit(struct repository *r,\n-\t\t\t\t\t struct commit_graph *g,\n+static struct tree *load_tree_for_commit(struct commit_graph *g,\n \t\t\t\t\t struct commit *c)\n {\n \tstruct object_id oid;\n@@ -1114,13 +1095,12 @@ static struct tree *load_tree_for_commit(struct repository *r,\n \t\t\t\tgraph_pos - g->num_commits_in_base);\n \n \toidread(&oid, commit_data, g->hash_algo);\n-\tset_commit_tree(c, lookup_tree(r, &oid));\n+\tset_commit_tree(c, lookup_tree(g->odb_source->odb->repo, &oid));\n \n \treturn c->maybe_tree;\n }\n \n-static struct tree *get_commit_tree_in_graph_one(struct repository *r,\n-\t\t\t\t\t\t struct commit_graph *g,\n+static struct tree *get_commit_tree_in_graph_one(struct commit_graph *g,\n \t\t\t\t\t\t const struct commit *c)\n {\n \tif (c->maybe_tree)\n@@ -1128,12 +1108,12 @@ static struct tree *get_commit_tree_in_graph_one(struct repository *r,\n \tif (commit_graph_position(c) == COMMIT_NOT_FROM_GRAPH)\n \t\tBUG(\"get_commit_tree_in_graph_one called from non-commit-graph commit\");\n \n-\treturn load_tree_for_commit(r, g, (struct commit *)c);\n+\treturn load_tree_for_commit(g, (struct commit *)c);\n }\n \n struct tree *get_commit_tree_in_graph(struct repository *r, const struct commit *c)\n {\n-\treturn get_commit_tree_in_graph_one(r, r->objects->commit_graph, c);\n+\treturn get_commit_tree_in_graph_one(r->objects->commit_graph, c);\n }\n \n struct packed_commit_list {\n@@ -2740,11 +2720,11 @@ static int commit_graph_checksum_valid(struct commit_graph *g)\n \t\t\t\t       g->data, g->data_len);\n }\n \n-static int verify_one_commit_graph(struct repository *r,\n-\t\t\t\t   struct commit_graph *g,\n+static int verify_one_commit_graph(struct commit_graph *g,\n \t\t\t\t   struct progress *progress,\n \t\t\t\t   uint64_t *seen)\n {\n+\tstruct repository *r = g->odb_source->odb->repo;\n \tuint32_t i, cur_fanout_pos = 0;\n \tstruct object_id prev_oid, cur_oid;\n \tstruct commit *seen_gen_zero = NULL;\n@@ -2778,7 +2758,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\t}\n \n \t\tgraph_commit = lookup_commit(r, &cur_oid);\n-\t\tif (!parse_commit_in_graph_one(r, g, graph_commit))\n+\t\tif (!parse_commit_in_graph_one(g, graph_commit))\n \t\t\tgraph_report(_(\"failed to parse commit %s from commit-graph\"),\n \t\t\t\t     oid_to_hex(&cur_oid));\n \t}\n@@ -2814,7 +2794,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\t\tcontinue;\n \t\t}\n \n-\t\tif (!oideq(&get_commit_tree_in_graph_one(r, g, graph_commit)->object.oid,\n+\t\tif (!oideq(&get_commit_tree_in_graph_one(g, graph_commit)->object.oid,\n \t\t\t   get_commit_tree_oid(odb_commit)))\n \t\t\tgraph_report(_(\"root tree OID for commit %s in commit-graph is %s != %s\"),\n \t\t\t\t     oid_to_hex(&cur_oid),\n@@ -2832,7 +2812,7 @@ static int verify_one_commit_graph(struct repository *r,\n \t\t\t}\n \n \t\t\t/* parse parent in case it is in a base graph */\n-\t\t\tparse_commit_in_graph_one(r, g, graph_parents->item);\n+\t\t\tparse_commit_in_graph_one(g, graph_parents->item);\n \n \t\t\tif (!oideq(&graph_parents->item->object.oid, &odb_parents->item->object.oid))\n \t\t\t\tgraph_report(_(\"commit-graph parent for %s is %s != %s\"),\n@@ -2892,7 +2872,7 @@ static int verify_one_commit_graph(struct repository *r,\n \treturn verify_commit_graph_error;\n }\n \n-int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n+int verify_commit_graph(struct commit_graph *g, int flags)\n {\n \tstruct progress *progress = NULL;\n \tint local_error = 0;\n@@ -2908,13 +2888,13 @@ int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags)\n \t\tif (!(flags & COMMIT_GRAPH_VERIFY_SHALLOW))\n \t\t\ttotal += g->num_commits_in_base;\n \n-\t\tprogress = start_progress(r,\n+\t\tprogress = start_progress(g->odb_source->odb->repo,\n \t\t\t\t\t  _(\"Verifying commits in commit graph\"),\n \t\t\t\t\t  total);\n \t}\n \n \tfor (; g; g = g->base_graph) {\n-\t\tlocal_error |= verify_one_commit_graph(r, g, progress, &seen);\n+\t\tlocal_error |= verify_one_commit_graph(g, progress, &seen);\n \t\tif (flags & COMMIT_GRAPH_VERIFY_SHALLOW)\n \t\t\tbreak;\n \t}\ndiff --git a/commit-graph.h b/commit-graph.h\nindex 0a67ac9280..4899b54ef8 100644\n--- a/commit-graph.h\n+++ b/commit-graph.h\n@@ -114,14 +114,12 @@ struct commit_graph {\n \tstruct bloom_filter_settings *bloom_filter_settings;\n };\n \n-struct commit_graph *load_commit_graph_one_fd_st(struct repository *r,\n-\t\t\t\t\t\t int fd, struct stat *st,\n-\t\t\t\t\t\t struct odb_source *source);\n-struct commit_graph *load_commit_graph_chain_fd_st(struct repository *r,\n+struct commit_graph *load_commit_graph_one_fd_st(struct odb_source *source,\n+\t\t\t\t\t\t int fd, struct stat *st);\n+struct commit_graph *load_commit_graph_chain_fd_st(struct object_database *odb,\n \t\t\t\t\t\t   int fd, struct stat *st,\n \t\t\t\t\t\t   int *incomplete_chain);\n-struct commit_graph *read_commit_graph_one(struct repository *r,\n-\t\t\t\t\t   struct odb_source *source);\n+struct commit_graph *read_commit_graph_one(struct odb_source *source);\n \n struct repo_settings;\n \n@@ -185,7 +183,7 @@ int write_commit_graph(struct odb_source *source,\n \n #define COMMIT_GRAPH_VERIFY_SHALLOW\t(1 << 0)\n \n-int verify_commit_graph(struct repository *r, struct commit_graph *g, int flags);\n+int verify_commit_graph(struct commit_graph *g, int flags);\n \n void close_commit_graph(struct object_database *);\n void free_commit_graph(struct commit_graph *);\ndiff --git a/t/helper/test-read-graph.c b/t/helper/test-read-graph.c\nindex ef5339bbee..6a5f64e473 100644\n--- a/t/helper/test-read-graph.c\n+++ b/t/helper/test-read-graph.c\n@@ -81,7 +81,7 @@ int cmd__read_graph(int argc, const char **argv)\n \n \tprepare_repo_settings(the_repository);\n \n-\tgraph = read_commit_graph_one(the_repository, source);\n+\tgraph = read_commit_graph_one(source);\n \tif (!graph) {\n \t\tret = 1;\n \t\tgoto done;\n\n-- \n2.51.0.rc1.215.g0f929dcec7.dirty\n\n"},{"id":"524243","messageId":"6704a016-781e-458e-96d9-2183b779a549@gmail.com","threadId":"63902","inReplyTo":"20250815-b4-pks-commit-graph-wo-the-repository-v4-0-b6b651178cce@pks.im","subject":"Re: [PATCH v4 0/6] commit-graph: remove reliance on global state","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2025-08-15T15:17:28Z","receivedAt":"2025-08-15T15:17:51Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 8/15/2025 1:49 AM, Patrick Steinhardt wrote:\n> Changes in v4:\n>   - Drop the patches that fix `-Wsign-compare` warnings.\n\nI appreciate the choice to leave the controversial changes\nfor a later series and instead focusing on refactoring-only\nchanges in this version. LGTM.\n\nThanks,\n-Stolee\n\n"}]}