{"thread":{"id":"64034","subject":"[GSoC][PATCH 0/5] Add refs optimize subcommand","startedAt":"2025-08-26T07:36:51Z","lastAt":"2025-09-03T18:20:59Z","messageCount":17,"participants":["Meet Soni","shejialuo","Patrick Steinhardt","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"524927","messageId":"20250826073645.1074397-1-meetsoni3017@gmail.com","threadId":"64034","inReplyTo":null,"subject":"[GSoC][PATCH 0/5] Add refs optimize subcommand","fromName":"Meet Soni","fromEmail":"meetsoni3017@gmail.com","sentAt":"2025-08-26T07:36:40Z","receivedAt":"2025-08-26T07:36:51Z","isPatch":true,"sender":{"key":"meetsoni3017@gmail.com","avatar":"https://avatars.githubusercontent.com/u/92802561?v=4"},"body":"This series introduces `git refs optimize` as a modern replacement for\n`git pack-refs`, continuing the effort to consolidate commands\nunder the `git refs` namespace.\n\nMeet Soni (5):\n  builtin/pack-refs: factor out core logic into a helper\n  doc: factor out common option\n  builtin/refs: add optimize subcommand\n  t0601: refactor tests to be shareable\n  t: add test for git refs optimize subcommand\n\n Documentation/git-pack-refs.adoc     |  54 +---\n Documentation/git-refs.adoc          |  10 +\n Documentation/pack-refs-options.adoc |  52 ++++\n builtin/pack-refs.c                  |  31 +-\n builtin/refs.c                       |  16 +\n pack-refs.h                          |  22 ++\n t/meson.build                        |   3 +-\n t/pack-refs-tests.sh                 | 431 +++++++++++++++++++++++++++\n t/t0601-reffiles-pack-refs.sh        | 430 +-------------------------\n t/t1463-refs-optimize.sh             |  17 ++\n 10 files changed, 572 insertions(+), 494 deletions(-)\n create mode 100644 Documentation/pack-refs-options.adoc\n create mode 100644 pack-refs.h\n create mode 100644 t/pack-refs-tests.sh\n create mode 100755 t/t1463-refs-optimize.sh\n\n\nbase-commit: 1fa68948c3d76328236cac73d2adf33c905bd8e3\n-- \n2.34.1\n\n"},{"id":"524928","messageId":"20250826073645.1074397-2-meetsoni3017@gmail.com","threadId":"64034","inReplyTo":"20250826073645.1074397-1-meetsoni3017@gmail.com","subject":"[GSoC][PATCH 1/5] builtin/pack-refs: factor out core logic into a helper","fromName":"Meet Soni","fromEmail":"meetsoni3017@gmail.com","sentAt":"2025-08-26T07:36:41Z","receivedAt":"2025-08-26T07:36:53Z","isPatch":true,"sender":{"key":"meetsoni3017@gmail.com","avatar":"https://avatars.githubusercontent.com/u/92802561?v=4"},"body":"The implementation of `git pack-refs` is monolithic within\n`cmd_pack_refs()`, making it impossible to share its logic with other\ncommands. To enable code reuse for the upcoming `git refs optimize`\nsubcommand, refactor the core logic into a shared helper function.\n\nIntroduce a new `pack-refs.h` header to define the public interface\nfor this shared logic. It contains the declaration for a new helper\nfunction, `pack_refs_core()`, and a macro for the common usage\noptions.\n\nMove the option parsing and packing logic from `cmd_pack_refs()` into a\nnew helper function named `pack_refs_core()`. This helper is made\ngeneric by accepting the command's usage string as a parameter.\n\nThe original `cmd_pack_refs()` is simplified to a thin wrapper that\nis only responsible for defining its specific usage array and calling\nthe shared helper.\n\nMentored-by: Patrick Steinhardt <ps@pks.im>\nMentored-by: shejialuo <shejialuo@gmail.com>\nSigned-off-by: Meet Soni <meetsoni3017@gmail.com>\n---\n builtin/pack-refs.c | 31 ++++++++++++++++++++-----------\n pack-refs.h         | 22 ++++++++++++++++++++++\n 2 files changed, 42 insertions(+), 11 deletions(-)\n create mode 100644 pack-refs.h\n\ndiff --git a/builtin/pack-refs.c b/builtin/pack-refs.c\nindex 5e28d0f9e8..7c4d7854c8 100644\n--- a/builtin/pack-refs.c\n+++ b/builtin/pack-refs.c\n@@ -2,19 +2,16 @@\n #include \"config.h\"\n #include \"environment.h\"\n #include \"gettext.h\"\n+#include \"pack-refs.h\"\n #include \"parse-options.h\"\n #include \"refs.h\"\n #include \"revision.h\"\n \n-static char const * const pack_refs_usage[] = {\n-\tN_(\"git pack-refs [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]\"),\n-\tNULL\n-};\n-\n-int cmd_pack_refs(int argc,\n-\t\t  const char **argv,\n-\t\t  const char *prefix,\n-\t\t  struct repository *repo)\n+int pack_refs_core(int argc,\n+\t\t   const char **argv,\n+\t\t   const char *prefix,\n+\t\t   struct repository *repo,\n+\t\t   const char * const *usage_opts)\n {\n \tstruct ref_exclusions excludes = REF_EXCLUSIONS_INIT;\n \tstruct string_list included_refs = STRING_LIST_INIT_NODUP;\n@@ -39,8 +36,8 @@ int cmd_pack_refs(int argc,\n \t\tOPT_END(),\n \t};\n \trepo_config(repo, git_default_config, NULL);\n-\tif (parse_options(argc, argv, prefix, opts, pack_refs_usage, 0))\n-\t\tusage_with_options(pack_refs_usage, opts);\n+\tif (parse_options(argc, argv, prefix, opts, usage_opts, 0))\n+\t\tusage_with_options(usage_opts, opts);\n \n \tfor_each_string_list_item(item, &option_excluded_refs)\n \t\tadd_ref_exclusion(pack_refs_opts.exclusions, item->string);\n@@ -58,3 +55,15 @@ int cmd_pack_refs(int argc,\n \tstring_list_clear(&option_excluded_refs, 0);\n \treturn ret;\n }\n+\n+int cmd_pack_refs(int argc,\n+\t\t  const char **argv,\n+\t\t  const char *prefix,\n+\t\t  struct repository *repo)\n+{\n+\tstatic char const * const pack_refs_usage[] = {\n+\t\tN_(\"git pack-refs \" PACK_REFS_OPTS),\n+\t\tNULL\n+\t};\n+\treturn pack_refs_core(argc, argv, prefix, repo, pack_refs_usage);\n+}\ndiff --git a/pack-refs.h b/pack-refs.h\nnew file mode 100644\nindex 0000000000..ba51d154e3\n--- /dev/null\n+++ b/pack-refs.h\n@@ -0,0 +1,22 @@\n+#ifndef PACK_REFS_H\n+#define PACK_REFS_H\n+\n+struct repository;\n+/*\n+ * Shared usage string for options common to git-pack-refs(1)\n+ * and git-refs-optimize(1). The command-specific part (e.g., \"git refs optimize \")\n+ * must be prepended by the caller.\n+ */\n+#define PACK_REFS_OPTS \\\n+\t\"[--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]\"\n+\n+/*\n+ * The core logic for pack-refs and its clones\n+ */\n+int pack_refs_core(int argc,\n+\t\t   const char **argv,\n+\t\t   const char *prefix,\n+\t\t   struct repository *repo,\n+\t\t   const char * const *usage_opts);\n+\n+#endif /* PACK_REFS_H */\n-- \n2.34.1\n\n"},{"id":"524929","messageId":"20250826073645.1074397-3-meetsoni3017@gmail.com","threadId":"64034","inReplyTo":"20250826073645.1074397-1-meetsoni3017@gmail.com","subject":"[GSoC][PATCH 2/5] doc: factor out common option","fromName":"Meet Soni","fromEmail":"meetsoni3017@gmail.com","sentAt":"2025-08-26T07:36:42Z","receivedAt":"2025-08-26T07:36:55Z","isPatch":true,"sender":{"key":"meetsoni3017@gmail.com","avatar":"https://avatars.githubusercontent.com/u/92802561?v=4"},"body":"In preparation for adding documentation for `git refs optimize`, factor\nout the common options from the `git-pack-refs` man page into a\nshareable file `pack-refs-options.adoc` and update `git-pack-refs.adoc`\nto use an `include::` macro.\n\nThis change is a pure refactoring and results in no change to the\nfinal rendered documentation for `pack-refs`.\n\nMentored-by: Patrick Steinhardt <ps@pks.im>\nMentored-by: shejialuo <shejialuo@gmail.com>\nSigned-off-by: Meet Soni <meetsoni3017@gmail.com>\n---\n Documentation/git-pack-refs.adoc     | 54 +---------------------------\n Documentation/pack-refs-options.adoc | 52 +++++++++++++++++++++++++++\n 2 files changed, 53 insertions(+), 53 deletions(-)\n create mode 100644 Documentation/pack-refs-options.adoc\n\ndiff --git a/Documentation/git-pack-refs.adoc b/Documentation/git-pack-refs.adoc\nindex 42b90051e6..dac63e5e12 100644\n--- a/Documentation/git-pack-refs.adoc\n+++ b/Documentation/git-pack-refs.adoc\n@@ -45,59 +45,7 @@ unpacked.\n OPTIONS\n -------\n \n---all::\n-\n-The command by default packs all tags and refs that are already\n-packed, and leaves other refs\n-alone.  This is because branches are expected to be actively\n-developed and packing their tips does not help performance.\n-This option causes all refs to be packed as well, with the exception\n-of hidden refs, broken refs, and symbolic refs. Useful for a repository\n-with many branches of historical interests.\n-\n---no-prune::\n-\n-The command usually removes loose refs under `$GIT_DIR/refs`\n-hierarchy after packing them.  This option tells it not to.\n-\n---auto::\n-\n-Pack refs as needed depending on the current state of the ref database. The\n-behavior depends on the ref format used by the repository and may change in the\n-future.\n-+\n-\t- \"files\": Loose references are packed into the `packed-refs` file\n-\t  based on the ratio of loose references to the size of the\n-\t  `packed-refs` file. The bigger the `packed-refs` file, the more loose\n-\t  references need to exist before we repack.\n-+\n-\t- \"reftable\": Tables are compacted such that they form a geometric\n-\t  sequence. For two tables N and N+1, where N+1 is newer, this\n-\t  maintains the property that N is at least twice as big as N+1. Only\n-\t  tables that violate this property are compacted.\n-\n---include <pattern>::\n-\n-Pack refs based on a `glob(7)` pattern. Repetitions of this option\n-accumulate inclusion patterns. If a ref is both included in `--include` and\n-`--exclude`, `--exclude` takes precedence. Using `--include` will preclude all\n-tags from being included by default. Symbolic refs and broken refs will never\n-be packed. When used with `--all`, it will be a noop. Use `--no-include` to clear\n-and reset the list of patterns.\n-\n---exclude <pattern>::\n-\n-Do not pack refs matching the given `glob(7)` pattern. Repetitions of this option\n-accumulate exclusion patterns. Use `--no-exclude` to clear and reset the list of\n-patterns. If a ref is already packed, including it with `--exclude` will not\n-unpack it.\n-+\n-When used with `--all`, pack only loose refs which do not match any of\n-the provided `--exclude` patterns.\n-+\n-When used with `--include`, refs provided to `--include`, minus refs that are\n-provided to `--exclude` will be packed.\n-\n+include::pack-refs-options.adoc[]\n \n BUGS\n ----\ndiff --git a/Documentation/pack-refs-options.adoc b/Documentation/pack-refs-options.adoc\nnew file mode 100644\nindex 0000000000..0b11282941\n--- /dev/null\n+++ b/Documentation/pack-refs-options.adoc\n@@ -0,0 +1,52 @@\n+--all::\n+\n+The command by default packs all tags and refs that are already\n+packed, and leaves other refs\n+alone.  This is because branches are expected to be actively\n+developed and packing their tips does not help performance.\n+This option causes all refs to be packed as well, with the exception\n+of hidden refs, broken refs, and symbolic refs. Useful for a repository\n+with many branches of historical interests.\n+\n+--no-prune::\n+\n+The command usually removes loose refs under `$GIT_DIR/refs`\n+hierarchy after packing them.  This option tells it not to.\n+\n+--auto::\n+\n+Pack refs as needed depending on the current state of the ref database. The\n+behavior depends on the ref format used by the repository and may change in the\n+future.\n++\n+\t- \"files\": Loose references are packed into the `packed-refs` file\n+\t  based on the ratio of loose references to the size of the\n+\t  `packed-refs` file. The bigger the `packed-refs` file, the more loose\n+\t  references need to exist before we repack.\n++\n+\t- \"reftable\": Tables are compacted such that they form a geometric\n+\t  sequence. For two tables N and N+1, where N+1 is newer, this\n+\t  maintains the property that N is at least twice as big as N+1. Only\n+\t  tables that violate this property are compacted.\n+\n+--include <pattern>::\n+\n+Pack refs based on a `glob(7)` pattern. Repetitions of this option\n+accumulate inclusion patterns. If a ref is both included in `--include` and\n+`--exclude`, `--exclude` takes precedence. Using `--include` will preclude all\n+tags from being included by default. Symbolic refs and broken refs will never\n+be packed. When used with `--all`, it will be a noop. Use `--no-include` to clear\n+and reset the list of patterns.\n+\n+--exclude <pattern>::\n+\n+Do not pack refs matching the given `glob(7)` pattern. Repetitions of this option\n+accumulate exclusion patterns. Use `--no-exclude` to clear and reset the list of\n+patterns. If a ref is already packed, including it with `--exclude` will not\n+unpack it.\n++\n+When used with `--all`, pack only loose refs which do not match any of\n+the provided `--exclude` patterns.\n++\n+When used with `--include`, refs provided to `--include`, minus refs that are\n+provided to `--exclude` will be packed.\n-- \n2.34.1\n\n"},{"id":"524930","messageId":"20250826073645.1074397-4-meetsoni3017@gmail.com","threadId":"64034","inReplyTo":"20250826073645.1074397-1-meetsoni3017@gmail.com","subject":"[GSoC][PATCH 3/5] builtin/refs: add optimize subcommand","fromName":"Meet Soni","fromEmail":"meetsoni3017@gmail.com","sentAt":"2025-08-26T07:36:43Z","receivedAt":"2025-08-26T07:36:57Z","isPatch":true,"sender":{"key":"meetsoni3017@gmail.com","avatar":"https://avatars.githubusercontent.com/u/92802561?v=4"},"body":"As part of the ongoing effort to consolidate reference handling,\nintroduce a new `optimize` subcommand. This command provides the same\nfunctionality and exit-code behavior as `git pack-refs`, serving\nas its modern replacement.\n\nImplement `cmd_refs_optimize` by having it call the `pack_refs_core()`\nhelper function. This helper was factored out of the original\n`cmd_pack_refs` in a preceding commit, allowing both commands to\nshare the same core logic as independent peers.\n\nAdd documentation for the new command. The man page leverages the shared\noptions file, created in a previous commit, by using the AsciiDoc\n`include::` macro to ensure consistency with git-pack-refs(1).\n\nMentored-by: Patrick Steinhardt <ps@pks.im>\nMentored-by: shejialuo <shejialuo@gmail.com>\nSigned-off-by: Meet Soni <meetsoni3017@gmail.com>\n---\n Documentation/git-refs.adoc | 10 ++++++++++\n builtin/refs.c              | 16 ++++++++++++++++\n 2 files changed, 26 insertions(+)\n\ndiff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc\nindex e608980711..121a2fbeff 100644\n--- a/Documentation/git-refs.adoc\n+++ b/Documentation/git-refs.adoc\n@@ -18,6 +18,7 @@ git refs list [--count=<count>] [--shell|--perl|--python|--tcl]\n \t\t   [--contains[=<object>]] [--no-contains[=<object>]]\n \t\t   [(--exclude=<pattern>)...] [--start-after=<marker>]\n \t\t   [ --stdin | <pattern>... ]\n+git refs optimize [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]\n \n DESCRIPTION\n -----------\n@@ -38,6 +39,11 @@ list::\n \tformatting, and sorting. This subcommand is an alias for\n \tlinkgit:git-for-each-ref[1] and offers identical functionality.\n \n+optimize::\n+        Pack references into a single file to improve repository performance\n+        and reduce storage usage. This subcommand is an alias for\n+        linkgit:git-pack-refs[1] and offers identical functionality.\n+\n OPTIONS\n -------\n \n@@ -73,6 +79,10 @@ The following options are specific to 'git refs list':\n \n include::for-each-ref-options.adoc[]\n \n+The following options are specific to 'git refs optimize':\n+\n+include::pack-refs-options.adoc[]\n+\n KNOWN LIMITATIONS\n -----------------\n \ndiff --git a/builtin/refs.c b/builtin/refs.c\nindex 76224feba4..e05fa5b8a6 100644\n--- a/builtin/refs.c\n+++ b/builtin/refs.c\n@@ -2,6 +2,7 @@\n #include \"builtin.h\"\n #include \"config.h\"\n #include \"fsck.h\"\n+#include \"pack-refs.h\"\n #include \"parse-options.h\"\n #include \"refs.h\"\n #include \"strbuf.h\"\n@@ -14,6 +15,9 @@\n #define REFS_VERIFY_USAGE \\\n \tN_(\"git refs verify [--strict] [--verbose]\")\n \n+#define REFS_OPTIMIZE_USAGE \\\n+\tN_(\"git refs optimize \" PACK_REFS_OPTS)\n+\n static int cmd_refs_migrate(int argc, const char **argv, const char *prefix,\n \t\t\t    struct repository *repo UNUSED)\n {\n@@ -113,6 +117,16 @@ static int cmd_refs_list(int argc, const char **argv, const char *prefix,\n \treturn for_each_ref_core(argc, argv, prefix, repo, refs_list_usage);\n }\n \n+static int cmd_refs_optimize(int argc, const char **argv, const char *prefix,\n+\t\t\t   struct repository *repo)\n+{\n+\tstatic char const * const refs_optimize_usage[] = {\n+\t\tREFS_OPTIMIZE_USAGE,\n+\t\tNULL\n+\t};\n+\treturn pack_refs_core(argc, argv, prefix, repo, refs_optimize_usage);\n+}\n+\n int cmd_refs(int argc,\n \t     const char **argv,\n \t     const char *prefix,\n@@ -122,6 +136,7 @@ int cmd_refs(int argc,\n \t\tREFS_MIGRATE_USAGE,\n \t\tREFS_VERIFY_USAGE,\n \t\t\"git refs list \" COMMON_USAGE_FOR_EACH_REF,\n+\t\tREFS_OPTIMIZE_USAGE,\n \t\tNULL,\n \t};\n \tparse_opt_subcommand_fn *fn = NULL;\n@@ -129,6 +144,7 @@ int cmd_refs(int argc,\n \t\tOPT_SUBCOMMAND(\"migrate\", &fn, cmd_refs_migrate),\n \t\tOPT_SUBCOMMAND(\"verify\", &fn, cmd_refs_verify),\n \t\tOPT_SUBCOMMAND(\"list\", &fn, cmd_refs_list),\n+\t\tOPT_SUBCOMMAND(\"optimize\", &fn, cmd_refs_optimize),\n \t\tOPT_END(),\n \t};\n \n-- \n2.34.1\n\n"},{"id":"524931","messageId":"20250826073645.1074397-5-meetsoni3017@gmail.com","threadId":"64034","inReplyTo":"20250826073645.1074397-1-meetsoni3017@gmail.com","subject":"[GSoC][PATCH 4/5] t0601: refactor tests to be shareable","fromName":"Meet Soni","fromEmail":"meetsoni3017@gmail.com","sentAt":"2025-08-26T07:36:44Z","receivedAt":"2025-08-26T07:37:00Z","isPatch":true,"sender":{"key":"meetsoni3017@gmail.com","avatar":"https://avatars.githubusercontent.com/u/92802561?v=4"},"body":"In preparation for adding tests for the new `git refs optimize` command,\nrefactor the existing t0601 test suite to make its logic shareable.\n\nMove the core test logic from `t0601-reffiles-pack-refs.sh` into a new\n`pack-refs-tests.sh` file. Inside this new script, replace hardcoded\ncalls to \"pack-refs\" with the `$pack_refs` variable.\n\nThe original `t0601-reffiles-pack-refs.sh` script now becomes a simple\n\"driver\". It is responsible for setting the default value of the\nvariable and then sourcing the test library.\n\nThis new structure follows the established pattern used for sharing\ntests between `git-for-each-ref` and `git-refs list` and prepares the test suite\nfor the `refs optimize` tests to be added in a subsequent commit.\n\nMentored-by: Patrick Steinhardt <ps@pks.im>\nMentored-by: shejialuo <shejialuo@gmail.com>\nSigned-off-by: Meet Soni <meetsoni3017@gmail.com>\n---\n t/pack-refs-tests.sh          | 431 ++++++++++++++++++++++++++++++++++\n t/t0601-reffiles-pack-refs.sh | 430 +--------------------------------\n 2 files changed, 432 insertions(+), 429 deletions(-)\n create mode 100644 t/pack-refs-tests.sh\n\ndiff --git a/t/pack-refs-tests.sh b/t/pack-refs-tests.sh\nnew file mode 100644\nindex 0000000000..3dbcc01718\n--- /dev/null\n+++ b/t/pack-refs-tests.sh\n@@ -0,0 +1,431 @@\n+pack_refs=${pack_refs:-pack-refs}\n+\n+test_expect_success 'enable reflogs' '\n+\tgit config core.logallrefupdates true\n+'\n+\n+test_expect_success 'prepare a trivial repository' '\n+\techo Hello > A &&\n+\tgit update-index --add A &&\n+\tgit commit -m \"Initial commit.\" &&\n+\tHEAD=$(git rev-parse --verify HEAD)\n+'\n+\n+test_expect_success '${pack_refs} --prune --all' '\n+\ttest_path_is_missing .git/packed-refs &&\n+\tgit ${pack_refs} --no-prune --all &&\n+\ttest_path_is_file .git/packed-refs &&\n+\tN=$(find .git/refs -type f | wc -l) &&\n+\ttest \"$N\" != 0 &&\n+\n+\tgit ${pack_refs} --prune --all &&\n+\ttest_path_is_file .git/packed-refs &&\n+\tN=$(find .git/refs -type f) &&\n+\ttest -z \"$N\"\n+'\n+\n+SHA1=\n+\n+test_expect_success 'see if git show-ref works as expected' '\n+\tgit branch a &&\n+\tSHA1=$(cat .git/refs/heads/a) &&\n+\techo \"$SHA1 refs/heads/a\" >expect &&\n+\tgit show-ref a >result &&\n+\ttest_cmp expect result\n+'\n+\n+test_expect_success 'see if a branch still exists when packed' '\n+\tgit branch b &&\n+\tgit ${pack_refs} --all &&\n+\trm -f .git/refs/heads/b &&\n+\techo \"$SHA1 refs/heads/b\" >expect &&\n+\tgit show-ref b >result &&\n+\ttest_cmp expect result\n+'\n+\n+test_expect_success 'git branch c/d should barf if branch c exists' '\n+\tgit branch c &&\n+\tgit ${pack_refs} --all &&\n+\trm -f .git/refs/heads/c &&\n+\ttest_must_fail git branch c/d\n+'\n+\n+test_expect_success 'see if a branch still exists after git ${pack_refs} --prune' '\n+\tgit branch e &&\n+\tgit ${pack_refs} --all --prune &&\n+\techo \"$SHA1 refs/heads/e\" >expect &&\n+\tgit show-ref e >result &&\n+\ttest_cmp expect result\n+'\n+\n+test_expect_success 'see if git ${pack_refs} --prune remove ref files' '\n+\tgit branch f &&\n+\tgit ${pack_refs} --all --prune &&\n+\t! test -f .git/refs/heads/f\n+'\n+\n+test_expect_success 'see if git ${pack_refs} --prune removes empty dirs' '\n+\tgit branch r/s/t &&\n+\tgit ${pack_refs} --all --prune &&\n+\t! test -e .git/refs/heads/r\n+'\n+\n+test_expect_success 'git branch g should work when git branch g/h has been deleted' '\n+\tgit branch g/h &&\n+\tgit ${pack_refs} --all --prune &&\n+\tgit branch -d g/h &&\n+\tgit branch g &&\n+\tgit ${pack_refs} --all &&\n+\tgit branch -d g\n+'\n+\n+test_expect_success 'git branch i/j/k should barf if branch i exists' '\n+\tgit branch i &&\n+\tgit ${pack_refs} --all --prune &&\n+\ttest_must_fail git branch i/j/k\n+'\n+\n+test_expect_success 'test git branch k after branch k/l/m and k/lm have been deleted' '\n+\tgit branch k/l &&\n+\tgit branch k/lm &&\n+\tgit branch -d k/l &&\n+\tgit branch k/l/m &&\n+\tgit branch -d k/l/m &&\n+\tgit branch -d k/lm &&\n+\tgit branch k\n+'\n+\n+test_expect_success 'test git branch n after some branch deletion and pruning' '\n+\tgit branch n/o &&\n+\tgit branch n/op &&\n+\tgit branch -d n/o &&\n+\tgit branch n/o/p &&\n+\tgit branch -d n/op &&\n+\tgit ${pack_refs} --all --prune &&\n+\tgit branch -d n/o/p &&\n+\tgit branch n\n+'\n+\n+test_expect_success 'test excluded refs are not packed' '\n+\tgit branch dont_pack1 &&\n+\tgit branch dont_pack2 &&\n+\tgit branch pack_this &&\n+\tgit ${pack_refs} --all --exclude \"refs/heads/dont_pack*\" &&\n+\ttest -f .git/refs/heads/dont_pack1 &&\n+\ttest -f .git/refs/heads/dont_pack2 &&\n+\t! test -f .git/refs/heads/pack_this'\n+\n+test_expect_success 'test --no-exclude refs clears excluded refs' '\n+\tgit branch dont_pack3 &&\n+\tgit branch dont_pack4 &&\n+\tgit ${pack_refs} --all --exclude \"refs/heads/dont_pack*\" --no-exclude &&\n+\t! test -f .git/refs/heads/dont_pack3 &&\n+\t! test -f .git/refs/heads/dont_pack4'\n+\n+test_expect_success 'test only included refs are packed' '\n+\tgit branch pack_this1 &&\n+\tgit branch pack_this2 &&\n+\tgit tag dont_pack5 &&\n+\tgit ${pack_refs} --include \"refs/heads/pack_this*\" &&\n+\ttest -f .git/refs/tags/dont_pack5 &&\n+\t! test -f .git/refs/heads/pack_this1 &&\n+\t! test -f .git/refs/heads/pack_this2'\n+\n+test_expect_success 'test --no-include refs clears included refs' '\n+\tgit branch pack1 &&\n+\tgit branch pack2 &&\n+\tgit ${pack_refs} --include \"refs/heads/pack*\" --no-include &&\n+\ttest -f .git/refs/heads/pack1 &&\n+\ttest -f .git/refs/heads/pack2'\n+\n+test_expect_success 'test --exclude takes precedence over --include' '\n+\tgit branch dont_pack5 &&\n+\tgit ${pack_refs} --include \"refs/heads/pack*\" --exclude \"refs/heads/pack*\" &&\n+\ttest -f .git/refs/heads/dont_pack5'\n+\n+test_expect_success 'see if up-to-date packed refs are preserved' '\n+\tgit branch q &&\n+\tgit ${pack_refs} --all --prune &&\n+\tgit update-ref refs/heads/q refs/heads/q &&\n+\t! test -f .git/refs/heads/q\n+'\n+\n+test_expect_success 'pack, prune and repack' '\n+\tgit tag foo &&\n+\tgit ${pack_refs} --all --prune &&\n+\tgit show-ref >all-of-them &&\n+\tgit ${pack_refs} &&\n+\tgit show-ref >again &&\n+\ttest_cmp all-of-them again\n+'\n+\n+test_expect_success 'explicit ${pack_refs} with dangling packed reference' '\n+\tgit commit --allow-empty -m \"soon to be garbage-collected\" &&\n+\tgit ${pack_refs} --all &&\n+\tgit reset --hard HEAD^ &&\n+\tgit reflog expire --expire=all --all &&\n+\tgit prune --expire=all &&\n+\tgit ${pack_refs} --all 2>result &&\n+\ttest_must_be_empty result\n+'\n+\n+test_expect_success 'delete ref with dangling packed version' '\n+\tgit checkout -b lamb &&\n+\tgit commit --allow-empty -m \"future garbage\" &&\n+\tgit ${pack_refs} --all &&\n+\tgit reset --hard HEAD^ &&\n+\tgit checkout main &&\n+\tgit reflog expire --expire=all --all &&\n+\tgit prune --expire=all &&\n+\tgit branch -d lamb 2>result &&\n+\ttest_must_be_empty result\n+'\n+\n+test_expect_success 'delete ref while another dangling packed ref' '\n+\tgit branch lamb &&\n+\tgit commit --allow-empty -m \"future garbage\" &&\n+\tgit ${pack_refs} --all &&\n+\tgit reset --hard HEAD^ &&\n+\tgit reflog expire --expire=all --all &&\n+\tgit prune --expire=all &&\n+\tgit branch -d lamb 2>result &&\n+\ttest_must_be_empty result\n+'\n+\n+test_expect_success 'pack ref directly below refs/' '\n+\tgit update-ref refs/top HEAD &&\n+\tgit ${pack_refs} --all --prune &&\n+\tgrep refs/top .git/packed-refs &&\n+\ttest_path_is_missing .git/refs/top\n+'\n+\n+test_expect_success 'do not pack ref in refs/bisect' '\n+\tgit update-ref refs/bisect/local HEAD &&\n+\tgit ${pack_refs} --all --prune &&\n+\t! grep refs/bisect/local .git/packed-refs >/dev/null &&\n+\ttest_path_is_file .git/refs/bisect/local\n+'\n+\n+test_expect_success 'disable reflogs' '\n+\tgit config core.logallrefupdates false &&\n+\trm -rf .git/logs\n+'\n+\n+test_expect_success 'create packed foo/bar/baz branch' '\n+\tgit branch foo/bar/baz &&\n+\tgit ${pack_refs} --all --prune &&\n+\ttest_path_is_missing .git/refs/heads/foo/bar/baz &&\n+\ttest_must_fail git reflog exists refs/heads/foo/bar/baz\n+'\n+\n+test_expect_success 'notice d/f conflict with existing directory' '\n+\ttest_must_fail git branch foo &&\n+\ttest_must_fail git branch foo/bar\n+'\n+\n+test_expect_success 'existing directory reports concrete ref' '\n+\ttest_must_fail git branch foo 2>stderr &&\n+\ttest_grep refs/heads/foo/bar/baz stderr\n+'\n+\n+test_expect_success 'notice d/f conflict with existing ref' '\n+\ttest_must_fail git branch foo/bar/baz/extra &&\n+\ttest_must_fail git branch foo/bar/baz/lots/of/extra/components\n+'\n+\n+test_expect_success 'reject packed-refs with unterminated line' '\n+\tcp .git/packed-refs .git/packed-refs.bak &&\n+\ttest_when_finished \"mv .git/packed-refs.bak .git/packed-refs\" &&\n+\tprintf \"%s\" \"$HEAD refs/zzzzz\" >>.git/packed-refs &&\n+\techo \"fatal: unterminated line in .git/packed-refs: $HEAD refs/zzzzz\" >expected_err &&\n+\ttest_must_fail git for-each-ref >out 2>err &&\n+\ttest_cmp expected_err err\n+'\n+\n+test_expect_success 'reject packed-refs containing junk' '\n+\tcp .git/packed-refs .git/packed-refs.bak &&\n+\ttest_when_finished \"mv .git/packed-refs.bak .git/packed-refs\" &&\n+\tprintf \"%s\\n\" \"bogus content\" >>.git/packed-refs &&\n+\techo \"fatal: unexpected line in .git/packed-refs: bogus content\" >expected_err &&\n+\ttest_must_fail git for-each-ref >out 2>err &&\n+\ttest_cmp expected_err err\n+'\n+\n+test_expect_success 'reject packed-refs with a short SHA-1' '\n+\tcp .git/packed-refs .git/packed-refs.bak &&\n+\ttest_when_finished \"mv .git/packed-refs.bak .git/packed-refs\" &&\n+\tprintf \"%.7s %s\\n\" $HEAD refs/zzzzz >>.git/packed-refs &&\n+\tprintf \"fatal: unexpected line in .git/packed-refs: %.7s %s\\n\" $HEAD refs/zzzzz >expected_err &&\n+\ttest_must_fail git for-each-ref >out 2>err &&\n+\ttest_cmp expected_err err\n+'\n+\n+test_expect_success 'timeout if packed-refs.lock exists' '\n+\tLOCK=.git/packed-refs.lock &&\n+\t>\"$LOCK\" &&\n+\ttest_when_finished \"rm -f $LOCK\" &&\n+\ttest_must_fail git ${pack_refs} --all --prune\n+'\n+\n+test_expect_success 'retry acquiring packed-refs.lock' '\n+\tLOCK=.git/packed-refs.lock &&\n+\t>\"$LOCK\" &&\n+\ttest_when_finished \"wait && rm -f $LOCK\" &&\n+\t{\n+\t\t( sleep 1 && rm -f $LOCK ) &\n+\t} &&\n+\tgit -c core.packedrefstimeout=3000 ${pack_refs} --all --prune\n+'\n+\n+test_expect_success SYMLINKS 'pack symlinked packed-refs' '\n+\t# First make sure that symlinking works when reading:\n+\tgit update-ref refs/heads/lossy refs/heads/main &&\n+\tgit for-each-ref >all-refs-before &&\n+\tmv .git/packed-refs .git/my-deviant-packed-refs &&\n+\tln -s my-deviant-packed-refs .git/packed-refs &&\n+\tgit for-each-ref >all-refs-linked &&\n+\ttest_cmp all-refs-before all-refs-linked &&\n+\tgit ${pack_refs} --all --prune &&\n+\tgit for-each-ref >all-refs-packed &&\n+\ttest_cmp all-refs-before all-refs-packed &&\n+\ttest -h .git/packed-refs &&\n+\ttest \"$(test_readlink .git/packed-refs)\" = \"my-deviant-packed-refs\"\n+'\n+\n+# The 'packed-refs' file is stored directly in .git/. This means it is global\n+# to the repository, and can only contain refs that are shared across all\n+# worktrees.\n+test_expect_success 'refs/worktree must not be packed' '\n+\ttest_commit initial &&\n+\ttest_commit wt1 &&\n+\ttest_commit wt2 &&\n+\tgit worktree add wt1 wt1 &&\n+\tgit worktree add wt2 wt2 &&\n+\tgit checkout initial &&\n+\tgit update-ref refs/worktree/foo HEAD &&\n+\tgit -C wt1 update-ref refs/worktree/foo HEAD &&\n+\tgit -C wt2 update-ref refs/worktree/foo HEAD &&\n+\tgit ${pack_refs} --all &&\n+\ttest_path_is_missing .git/refs/tags/wt1 &&\n+\ttest_path_is_file .git/refs/worktree/foo &&\n+\ttest_path_is_file .git/worktrees/wt1/refs/worktree/foo &&\n+\ttest_path_is_file .git/worktrees/wt2/refs/worktree/foo\n+'\n+\n+# we do not want to count on running ${pack_refs} to\n+# actually pack it, as it is perfectly reasonable to\n+# skip processing a broken ref\n+test_expect_success 'create packed-refs file with broken ref' '\n+\ttest_tick && git commit --allow-empty -m one &&\n+\trecoverable=$(git rev-parse HEAD) &&\n+\ttest_tick && git commit --allow-empty -m two &&\n+\tmissing=$(git rev-parse HEAD) &&\n+\trm -f .git/refs/heads/main &&\n+\tcat >.git/packed-refs <<-EOF &&\n+\t$missing refs/heads/main\n+\t$recoverable refs/heads/other\n+\tEOF\n+\techo $missing >expect &&\n+\tgit rev-parse refs/heads/main >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '${pack_refs} does not silently delete broken packed ref' '\n+\tgit ${pack_refs} --all --prune &&\n+\tgit rev-parse refs/heads/main >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+test_expect_success '${pack_refs} does not drop broken refs during deletion' '\n+\tgit update-ref -d refs/heads/other &&\n+\tgit rev-parse refs/heads/main >actual &&\n+\ttest_cmp expect actual\n+'\n+\n+for command in \"git ${pack_refs} --all --auto\" \"git maintenance run --task=${pack_refs} --auto\"\n+do\n+\ttest_expect_success \"$command does not repack below 16 refs without packed-refs\" '\n+\t\ttest_when_finished \"rm -rf repo\" &&\n+\t\tgit init repo &&\n+\t\t(\n+\t\t\tcd repo &&\n+\t\t\tgit config set maintenance.auto false &&\n+\t\t\tgit commit --allow-empty --message \"initial\" &&\n+\n+\t\t\t# Create 14 additional references, which brings us to\n+\t\t\t# 15 together with the default branch.\n+\t\t\tprintf \"create refs/heads/loose-%d HEAD\\n\" $(test_seq 14) >stdin &&\n+\t\t\tgit update-ref --stdin <stdin &&\n+\t\t\ttest_path_is_missing .git/packed-refs &&\n+\t\t\tgit ${pack_refs} --auto --all &&\n+\t\t\ttest_path_is_missing .git/packed-refs &&\n+\n+\t\t\t# Create the 16th reference, which should cause us to repack.\n+\t\t\tgit update-ref refs/heads/loose-15 HEAD &&\n+\t\t\tgit ${pack_refs} --auto --all &&\n+\t\t\ttest_path_is_file .git/packed-refs\n+\t\t)\n+\t'\n+\n+\ttest_expect_success \"$command does not repack below 16 refs with small packed-refs\" '\n+\t\ttest_when_finished \"rm -rf repo\" &&\n+\t\tgit init repo &&\n+\t\t(\n+\t\t\tcd repo &&\n+\t\t\tgit config set maintenance.auto false &&\n+\t\t\tgit commit --allow-empty --message \"initial\" &&\n+\n+\t\t\tgit ${pack_refs} --all &&\n+\t\t\ttest_line_count = 2 .git/packed-refs &&\n+\n+\t\t\t# Create 15 loose references.\n+\t\t\tprintf \"create refs/heads/loose-%d HEAD\\n\" $(test_seq 15) >stdin &&\n+\t\t\tgit update-ref --stdin <stdin &&\n+\t\t\tgit ${pack_refs} --auto --all &&\n+\t\t\ttest_line_count = 2 .git/packed-refs &&\n+\n+\t\t\t# Create the 16th loose reference, which should cause us to repack.\n+\t\t\tgit update-ref refs/heads/loose-17 HEAD &&\n+\t\t\tgit ${pack_refs} --auto --all &&\n+\t\t\ttest_line_count = 18 .git/packed-refs\n+\t\t)\n+\t'\n+\n+\ttest_expect_success \"$command scales with size of packed-refs\" '\n+\t\ttest_when_finished \"rm -rf repo\" &&\n+\t\tgit init repo &&\n+\t\t(\n+\t\t\tcd repo &&\n+\t\t\tgit config set maintenance.auto false &&\n+\t\t\tgit commit --allow-empty --message \"initial\" &&\n+\n+\t\t\t# Create 99 packed refs. This should cause the heuristic\n+\t\t\t# to require more than the minimum amount of loose refs.\n+\t\t\ttest_seq 99 |\n+\t\t\twhile read i\n+\t\t\tdo\n+\t\t\t\tprintf \"create refs/heads/packed-%d HEAD\\n\" $i || return 1\n+\t\t\tdone >stdin &&\n+\t\t\tgit update-ref --stdin <stdin &&\n+\t\t\tgit ${pack_refs} --all &&\n+\t\t\ttest_line_count = 101 .git/packed-refs &&\n+\n+\t\t\t# Create 24 loose refs, which should not yet cause us to repack.\n+\t\t\tprintf \"create refs/heads/loose-%d HEAD\\n\" $(test_seq 24) >stdin &&\n+\t\t\tgit update-ref --stdin <stdin &&\n+\t\t\tgit ${pack_refs} --auto --all &&\n+\t\t\ttest_line_count = 101 .git/packed-refs &&\n+\n+\t\t\t# Create another handful of refs to cross the border.\n+\t\t\t# Note that we explicitly do not check for strict\n+\t\t\t# boundaries here, as this also depends on the size of\n+\t\t\t# the object hash.\n+\t\t\tprintf \"create refs/heads/addn-%d HEAD\\n\" $(test_seq 10) >stdin &&\n+\t\t\tgit update-ref --stdin <stdin &&\n+\t\t\tgit ${pack_refs} --auto --all &&\n+\t\t\ttest_line_count = 135 .git/packed-refs\n+\t\t)\n+\t'\n+done\n+\n+test_done\ndiff --git a/t/t0601-reffiles-pack-refs.sh b/t/t0601-reffiles-pack-refs.sh\nindex aa7f6ecd81..12cf5d1dcb 100755\n--- a/t/t0601-reffiles-pack-refs.sh\n+++ b/t/t0601-reffiles-pack-refs.sh\n@@ -17,432 +17,4 @@ export GIT_TEST_DEFAULT_REF_FORMAT\n \n . ./test-lib.sh\n \n-test_expect_success 'enable reflogs' '\n-\tgit config core.logallrefupdates true\n-'\n-\n-test_expect_success 'prepare a trivial repository' '\n-\techo Hello > A &&\n-\tgit update-index --add A &&\n-\tgit commit -m \"Initial commit.\" &&\n-\tHEAD=$(git rev-parse --verify HEAD)\n-'\n-\n-test_expect_success 'pack-refs --prune --all' '\n-\ttest_path_is_missing .git/packed-refs &&\n-\tgit pack-refs --no-prune --all &&\n-\ttest_path_is_file .git/packed-refs &&\n-\tN=$(find .git/refs -type f | wc -l) &&\n-\ttest \"$N\" != 0 &&\n-\n-\tgit pack-refs --prune --all &&\n-\ttest_path_is_file .git/packed-refs &&\n-\tN=$(find .git/refs -type f) &&\n-\ttest -z \"$N\"\n-'\n-\n-SHA1=\n-\n-test_expect_success 'see if git show-ref works as expected' '\n-\tgit branch a &&\n-\tSHA1=$(cat .git/refs/heads/a) &&\n-\techo \"$SHA1 refs/heads/a\" >expect &&\n-\tgit show-ref a >result &&\n-\ttest_cmp expect result\n-'\n-\n-test_expect_success 'see if a branch still exists when packed' '\n-\tgit branch b &&\n-\tgit pack-refs --all &&\n-\trm -f .git/refs/heads/b &&\n-\techo \"$SHA1 refs/heads/b\" >expect &&\n-\tgit show-ref b >result &&\n-\ttest_cmp expect result\n-'\n-\n-test_expect_success 'git branch c/d should barf if branch c exists' '\n-\tgit branch c &&\n-\tgit pack-refs --all &&\n-\trm -f .git/refs/heads/c &&\n-\ttest_must_fail git branch c/d\n-'\n-\n-test_expect_success 'see if a branch still exists after git pack-refs --prune' '\n-\tgit branch e &&\n-\tgit pack-refs --all --prune &&\n-\techo \"$SHA1 refs/heads/e\" >expect &&\n-\tgit show-ref e >result &&\n-\ttest_cmp expect result\n-'\n-\n-test_expect_success 'see if git pack-refs --prune remove ref files' '\n-\tgit branch f &&\n-\tgit pack-refs --all --prune &&\n-\t! test -f .git/refs/heads/f\n-'\n-\n-test_expect_success 'see if git pack-refs --prune removes empty dirs' '\n-\tgit branch r/s/t &&\n-\tgit pack-refs --all --prune &&\n-\t! test -e .git/refs/heads/r\n-'\n-\n-test_expect_success 'git branch g should work when git branch g/h has been deleted' '\n-\tgit branch g/h &&\n-\tgit pack-refs --all --prune &&\n-\tgit branch -d g/h &&\n-\tgit branch g &&\n-\tgit pack-refs --all &&\n-\tgit branch -d g\n-'\n-\n-test_expect_success 'git branch i/j/k should barf if branch i exists' '\n-\tgit branch i &&\n-\tgit pack-refs --all --prune &&\n-\ttest_must_fail git branch i/j/k\n-'\n-\n-test_expect_success 'test git branch k after branch k/l/m and k/lm have been deleted' '\n-\tgit branch k/l &&\n-\tgit branch k/lm &&\n-\tgit branch -d k/l &&\n-\tgit branch k/l/m &&\n-\tgit branch -d k/l/m &&\n-\tgit branch -d k/lm &&\n-\tgit branch k\n-'\n-\n-test_expect_success 'test git branch n after some branch deletion and pruning' '\n-\tgit branch n/o &&\n-\tgit branch n/op &&\n-\tgit branch -d n/o &&\n-\tgit branch n/o/p &&\n-\tgit branch -d n/op &&\n-\tgit pack-refs --all --prune &&\n-\tgit branch -d n/o/p &&\n-\tgit branch n\n-'\n-\n-test_expect_success 'test excluded refs are not packed' '\n-\tgit branch dont_pack1 &&\n-\tgit branch dont_pack2 &&\n-\tgit branch pack_this &&\n-\tgit pack-refs --all --exclude \"refs/heads/dont_pack*\" &&\n-\ttest -f .git/refs/heads/dont_pack1 &&\n-\ttest -f .git/refs/heads/dont_pack2 &&\n-\t! test -f .git/refs/heads/pack_this'\n-\n-test_expect_success 'test --no-exclude refs clears excluded refs' '\n-\tgit branch dont_pack3 &&\n-\tgit branch dont_pack4 &&\n-\tgit pack-refs --all --exclude \"refs/heads/dont_pack*\" --no-exclude &&\n-\t! test -f .git/refs/heads/dont_pack3 &&\n-\t! test -f .git/refs/heads/dont_pack4'\n-\n-test_expect_success 'test only included refs are packed' '\n-\tgit branch pack_this1 &&\n-\tgit branch pack_this2 &&\n-\tgit tag dont_pack5 &&\n-\tgit pack-refs --include \"refs/heads/pack_this*\" &&\n-\ttest -f .git/refs/tags/dont_pack5 &&\n-\t! test -f .git/refs/heads/pack_this1 &&\n-\t! test -f .git/refs/heads/pack_this2'\n-\n-test_expect_success 'test --no-include refs clears included refs' '\n-\tgit branch pack1 &&\n-\tgit branch pack2 &&\n-\tgit pack-refs --include \"refs/heads/pack*\" --no-include &&\n-\ttest -f .git/refs/heads/pack1 &&\n-\ttest -f .git/refs/heads/pack2'\n-\n-test_expect_success 'test --exclude takes precedence over --include' '\n-\tgit branch dont_pack5 &&\n-\tgit pack-refs --include \"refs/heads/pack*\" --exclude \"refs/heads/pack*\" &&\n-\ttest -f .git/refs/heads/dont_pack5'\n-\n-test_expect_success 'see if up-to-date packed refs are preserved' '\n-\tgit branch q &&\n-\tgit pack-refs --all --prune &&\n-\tgit update-ref refs/heads/q refs/heads/q &&\n-\t! test -f .git/refs/heads/q\n-'\n-\n-test_expect_success 'pack, prune and repack' '\n-\tgit tag foo &&\n-\tgit pack-refs --all --prune &&\n-\tgit show-ref >all-of-them &&\n-\tgit pack-refs &&\n-\tgit show-ref >again &&\n-\ttest_cmp all-of-them again\n-'\n-\n-test_expect_success 'explicit pack-refs with dangling packed reference' '\n-\tgit commit --allow-empty -m \"soon to be garbage-collected\" &&\n-\tgit pack-refs --all &&\n-\tgit reset --hard HEAD^ &&\n-\tgit reflog expire --expire=all --all &&\n-\tgit prune --expire=all &&\n-\tgit pack-refs --all 2>result &&\n-\ttest_must_be_empty result\n-'\n-\n-test_expect_success 'delete ref with dangling packed version' '\n-\tgit checkout -b lamb &&\n-\tgit commit --allow-empty -m \"future garbage\" &&\n-\tgit pack-refs --all &&\n-\tgit reset --hard HEAD^ &&\n-\tgit checkout main &&\n-\tgit reflog expire --expire=all --all &&\n-\tgit prune --expire=all &&\n-\tgit branch -d lamb 2>result &&\n-\ttest_must_be_empty result\n-'\n-\n-test_expect_success 'delete ref while another dangling packed ref' '\n-\tgit branch lamb &&\n-\tgit commit --allow-empty -m \"future garbage\" &&\n-\tgit pack-refs --all &&\n-\tgit reset --hard HEAD^ &&\n-\tgit reflog expire --expire=all --all &&\n-\tgit prune --expire=all &&\n-\tgit branch -d lamb 2>result &&\n-\ttest_must_be_empty result\n-'\n-\n-test_expect_success 'pack ref directly below refs/' '\n-\tgit update-ref refs/top HEAD &&\n-\tgit pack-refs --all --prune &&\n-\tgrep refs/top .git/packed-refs &&\n-\ttest_path_is_missing .git/refs/top\n-'\n-\n-test_expect_success 'do not pack ref in refs/bisect' '\n-\tgit update-ref refs/bisect/local HEAD &&\n-\tgit pack-refs --all --prune &&\n-\t! grep refs/bisect/local .git/packed-refs >/dev/null &&\n-\ttest_path_is_file .git/refs/bisect/local\n-'\n-\n-test_expect_success 'disable reflogs' '\n-\tgit config core.logallrefupdates false &&\n-\trm -rf .git/logs\n-'\n-\n-test_expect_success 'create packed foo/bar/baz branch' '\n-\tgit branch foo/bar/baz &&\n-\tgit pack-refs --all --prune &&\n-\ttest_path_is_missing .git/refs/heads/foo/bar/baz &&\n-\ttest_must_fail git reflog exists refs/heads/foo/bar/baz\n-'\n-\n-test_expect_success 'notice d/f conflict with existing directory' '\n-\ttest_must_fail git branch foo &&\n-\ttest_must_fail git branch foo/bar\n-'\n-\n-test_expect_success 'existing directory reports concrete ref' '\n-\ttest_must_fail git branch foo 2>stderr &&\n-\ttest_grep refs/heads/foo/bar/baz stderr\n-'\n-\n-test_expect_success 'notice d/f conflict with existing ref' '\n-\ttest_must_fail git branch foo/bar/baz/extra &&\n-\ttest_must_fail git branch foo/bar/baz/lots/of/extra/components\n-'\n-\n-test_expect_success 'reject packed-refs with unterminated line' '\n-\tcp .git/packed-refs .git/packed-refs.bak &&\n-\ttest_when_finished \"mv .git/packed-refs.bak .git/packed-refs\" &&\n-\tprintf \"%s\" \"$HEAD refs/zzzzz\" >>.git/packed-refs &&\n-\techo \"fatal: unterminated line in .git/packed-refs: $HEAD refs/zzzzz\" >expected_err &&\n-\ttest_must_fail git for-each-ref >out 2>err &&\n-\ttest_cmp expected_err err\n-'\n-\n-test_expect_success 'reject packed-refs containing junk' '\n-\tcp .git/packed-refs .git/packed-refs.bak &&\n-\ttest_when_finished \"mv .git/packed-refs.bak .git/packed-refs\" &&\n-\tprintf \"%s\\n\" \"bogus content\" >>.git/packed-refs &&\n-\techo \"fatal: unexpected line in .git/packed-refs: bogus content\" >expected_err &&\n-\ttest_must_fail git for-each-ref >out 2>err &&\n-\ttest_cmp expected_err err\n-'\n-\n-test_expect_success 'reject packed-refs with a short SHA-1' '\n-\tcp .git/packed-refs .git/packed-refs.bak &&\n-\ttest_when_finished \"mv .git/packed-refs.bak .git/packed-refs\" &&\n-\tprintf \"%.7s %s\\n\" $HEAD refs/zzzzz >>.git/packed-refs &&\n-\tprintf \"fatal: unexpected line in .git/packed-refs: %.7s %s\\n\" $HEAD refs/zzzzz >expected_err &&\n-\ttest_must_fail git for-each-ref >out 2>err &&\n-\ttest_cmp expected_err err\n-'\n-\n-test_expect_success 'timeout if packed-refs.lock exists' '\n-\tLOCK=.git/packed-refs.lock &&\n-\t>\"$LOCK\" &&\n-\ttest_when_finished \"rm -f $LOCK\" &&\n-\ttest_must_fail git pack-refs --all --prune\n-'\n-\n-test_expect_success 'retry acquiring packed-refs.lock' '\n-\tLOCK=.git/packed-refs.lock &&\n-\t>\"$LOCK\" &&\n-\ttest_when_finished \"wait && rm -f $LOCK\" &&\n-\t{\n-\t\t( sleep 1 && rm -f $LOCK ) &\n-\t} &&\n-\tgit -c core.packedrefstimeout=3000 pack-refs --all --prune\n-'\n-\n-test_expect_success SYMLINKS 'pack symlinked packed-refs' '\n-\t# First make sure that symlinking works when reading:\n-\tgit update-ref refs/heads/lossy refs/heads/main &&\n-\tgit for-each-ref >all-refs-before &&\n-\tmv .git/packed-refs .git/my-deviant-packed-refs &&\n-\tln -s my-deviant-packed-refs .git/packed-refs &&\n-\tgit for-each-ref >all-refs-linked &&\n-\ttest_cmp all-refs-before all-refs-linked &&\n-\tgit pack-refs --all --prune &&\n-\tgit for-each-ref >all-refs-packed &&\n-\ttest_cmp all-refs-before all-refs-packed &&\n-\ttest -h .git/packed-refs &&\n-\ttest \"$(test_readlink .git/packed-refs)\" = \"my-deviant-packed-refs\"\n-'\n-\n-# The 'packed-refs' file is stored directly in .git/. This means it is global\n-# to the repository, and can only contain refs that are shared across all\n-# worktrees.\n-test_expect_success 'refs/worktree must not be packed' '\n-\ttest_commit initial &&\n-\ttest_commit wt1 &&\n-\ttest_commit wt2 &&\n-\tgit worktree add wt1 wt1 &&\n-\tgit worktree add wt2 wt2 &&\n-\tgit checkout initial &&\n-\tgit update-ref refs/worktree/foo HEAD &&\n-\tgit -C wt1 update-ref refs/worktree/foo HEAD &&\n-\tgit -C wt2 update-ref refs/worktree/foo HEAD &&\n-\tgit pack-refs --all &&\n-\ttest_path_is_missing .git/refs/tags/wt1 &&\n-\ttest_path_is_file .git/refs/worktree/foo &&\n-\ttest_path_is_file .git/worktrees/wt1/refs/worktree/foo &&\n-\ttest_path_is_file .git/worktrees/wt2/refs/worktree/foo\n-'\n-\n-# we do not want to count on running pack-refs to\n-# actually pack it, as it is perfectly reasonable to\n-# skip processing a broken ref\n-test_expect_success 'create packed-refs file with broken ref' '\n-\ttest_tick && git commit --allow-empty -m one &&\n-\trecoverable=$(git rev-parse HEAD) &&\n-\ttest_tick && git commit --allow-empty -m two &&\n-\tmissing=$(git rev-parse HEAD) &&\n-\trm -f .git/refs/heads/main &&\n-\tcat >.git/packed-refs <<-EOF &&\n-\t$missing refs/heads/main\n-\t$recoverable refs/heads/other\n-\tEOF\n-\techo $missing >expect &&\n-\tgit rev-parse refs/heads/main >actual &&\n-\ttest_cmp expect actual\n-'\n-\n-test_expect_success 'pack-refs does not silently delete broken packed ref' '\n-\tgit pack-refs --all --prune &&\n-\tgit rev-parse refs/heads/main >actual &&\n-\ttest_cmp expect actual\n-'\n-\n-test_expect_success 'pack-refs does not drop broken refs during deletion' '\n-\tgit update-ref -d refs/heads/other &&\n-\tgit rev-parse refs/heads/main >actual &&\n-\ttest_cmp expect actual\n-'\n-\n-for command in \"git pack-refs --all --auto\" \"git maintenance run --task=pack-refs --auto\"\n-do\n-\ttest_expect_success \"$command does not repack below 16 refs without packed-refs\" '\n-\t\ttest_when_finished \"rm -rf repo\" &&\n-\t\tgit init repo &&\n-\t\t(\n-\t\t\tcd repo &&\n-\t\t\tgit config set maintenance.auto false &&\n-\t\t\tgit commit --allow-empty --message \"initial\" &&\n-\n-\t\t\t# Create 14 additional references, which brings us to\n-\t\t\t# 15 together with the default branch.\n-\t\t\tprintf \"create refs/heads/loose-%d HEAD\\n\" $(test_seq 14) >stdin &&\n-\t\t\tgit update-ref --stdin <stdin &&\n-\t\t\ttest_path_is_missing .git/packed-refs &&\n-\t\t\tgit pack-refs --auto --all &&\n-\t\t\ttest_path_is_missing .git/packed-refs &&\n-\n-\t\t\t# Create the 16th reference, which should cause us to repack.\n-\t\t\tgit update-ref refs/heads/loose-15 HEAD &&\n-\t\t\tgit pack-refs --auto --all &&\n-\t\t\ttest_path_is_file .git/packed-refs\n-\t\t)\n-\t'\n-\n-\ttest_expect_success \"$command does not repack below 16 refs with small packed-refs\" '\n-\t\ttest_when_finished \"rm -rf repo\" &&\n-\t\tgit init repo &&\n-\t\t(\n-\t\t\tcd repo &&\n-\t\t\tgit config set maintenance.auto false &&\n-\t\t\tgit commit --allow-empty --message \"initial\" &&\n-\n-\t\t\tgit pack-refs --all &&\n-\t\t\ttest_line_count = 2 .git/packed-refs &&\n-\n-\t\t\t# Create 15 loose references.\n-\t\t\tprintf \"create refs/heads/loose-%d HEAD\\n\" $(test_seq 15) >stdin &&\n-\t\t\tgit update-ref --stdin <stdin &&\n-\t\t\tgit pack-refs --auto --all &&\n-\t\t\ttest_line_count = 2 .git/packed-refs &&\n-\n-\t\t\t# Create the 16th loose reference, which should cause us to repack.\n-\t\t\tgit update-ref refs/heads/loose-17 HEAD &&\n-\t\t\tgit pack-refs --auto --all &&\n-\t\t\ttest_line_count = 18 .git/packed-refs\n-\t\t)\n-\t'\n-\n-\ttest_expect_success \"$command scales with size of packed-refs\" '\n-\t\ttest_when_finished \"rm -rf repo\" &&\n-\t\tgit init repo &&\n-\t\t(\n-\t\t\tcd repo &&\n-\t\t\tgit config set maintenance.auto false &&\n-\t\t\tgit commit --allow-empty --message \"initial\" &&\n-\n-\t\t\t# Create 99 packed refs. This should cause the heuristic\n-\t\t\t# to require more than the minimum amount of loose refs.\n-\t\t\ttest_seq 99 |\n-\t\t\twhile read i\n-\t\t\tdo\n-\t\t\t\tprintf \"create refs/heads/packed-%d HEAD\\n\" $i || return 1\n-\t\t\tdone >stdin &&\n-\t\t\tgit update-ref --stdin <stdin &&\n-\t\t\tgit pack-refs --all &&\n-\t\t\ttest_line_count = 101 .git/packed-refs &&\n-\n-\t\t\t# Create 24 loose refs, which should not yet cause us to repack.\n-\t\t\tprintf \"create refs/heads/loose-%d HEAD\\n\" $(test_seq 24) >stdin &&\n-\t\t\tgit update-ref --stdin <stdin &&\n-\t\t\tgit pack-refs --auto --all &&\n-\t\t\ttest_line_count = 101 .git/packed-refs &&\n-\n-\t\t\t# Create another handful of refs to cross the border.\n-\t\t\t# Note that we explicitly do not check for strict\n-\t\t\t# boundaries here, as this also depends on the size of\n-\t\t\t# the object hash.\n-\t\t\tprintf \"create refs/heads/addn-%d HEAD\\n\" $(test_seq 10) >stdin &&\n-\t\t\tgit update-ref --stdin <stdin &&\n-\t\t\tgit pack-refs --auto --all &&\n-\t\t\ttest_line_count = 135 .git/packed-refs\n-\t\t)\n-\t'\n-done\n-\n-test_done\n+. \"$TEST_DIRECTORY\"/pack-refs-tests.sh\n-- \n2.34.1\n\n"},{"id":"524932","messageId":"20250826073645.1074397-6-meetsoni3017@gmail.com","threadId":"64034","inReplyTo":"20250826073645.1074397-1-meetsoni3017@gmail.com","subject":"[GSoC][PATCH 5/5] t: add test for git refs optimize subcommand","fromName":"Meet Soni","fromEmail":"meetsoni3017@gmail.com","sentAt":"2025-08-26T07:36:45Z","receivedAt":"2025-08-26T07:37:02Z","isPatch":true,"sender":{"key":"meetsoni3017@gmail.com","avatar":"https://avatars.githubusercontent.com/u/92802561?v=4"},"body":"Add a test script, `t/t1463-refs-optimize.sh`, for the new `git refs\noptimize` command.\n\nThis script acts as a simple driver, leveraging the shared test library\ncreated in the preceding commit. It works by overriding the\n`$pack_refs` variable to \"refs optimize\" and then sourcing the\nshared library (`t/pack-refs-tests.sh`).\n\nThis approach ensures that `git refs optimize` is tested against the\nentire comprehensive test suite of `git pack-refs`, verifying\nthat it acts as a compatible drop-in replacement.\n\nMentored-by: Patrick Steinhardt <ps@pks.im>\nMentored-by: shejialuo <shejialuo@gmail.com>\nSigned-off-by: Meet Soni <meetsoni3017@gmail.com>\n---\n t/meson.build            |  3 ++-\n t/t1463-refs-optimize.sh | 17 +++++++++++++++++\n 2 files changed, 19 insertions(+), 1 deletion(-)\n create mode 100755 t/t1463-refs-optimize.sh\n\ndiff --git a/t/meson.build b/t/meson.build\nindex daf01fb5d0..48f83e12a7 100644\n--- a/t/meson.build\n+++ b/t/meson.build\n@@ -210,6 +210,7 @@ integration_tests = [\n   't1451-fsck-buffer.sh',\n   't1460-refs-migrate.sh',\n   't1461-refs-list.sh',\n+  't1463-refs-optimize.sh',\n   't1500-rev-parse.sh',\n   't1501-work-tree.sh',\n   't1502-rev-parse-parseopt.sh',\n@@ -1216,4 +1217,4 @@ if perl.found() and time.found()\n       timeout: 0,\n     )\n   endforeach\n-endif\n\\ No newline at end of file\n+endif\ndiff --git a/t/t1463-refs-optimize.sh b/t/t1463-refs-optimize.sh\nnew file mode 100755\nindex 0000000000..c11c905d79\n--- /dev/null\n+++ b/t/t1463-refs-optimize.sh\n@@ -0,0 +1,17 @@\n+#!/bin/sh\n+\n+test_description='git refs optimize should not change the branch semantic\n+\n+This test runs git refs optimize and git show-ref and checks that the branch\n+semantic is still the same.\n+'\n+\n+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main\n+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n+GIT_TEST_DEFAULT_REF_FORMAT=files\n+export GIT_TEST_DEFAULT_REF_FORMAT\n+\n+. ./test-lib.sh\n+\n+pack_refs='refs optimize'\n+. \"$TEST_DIRECTORY\"/pack-refs-tests.sh\n-- \n2.34.1\n\n"},{"id":"524965","messageId":"aK3QOtQzUFsGvmyA@ArchLinux","threadId":"64034","inReplyTo":"20250826073645.1074397-6-meetsoni3017@gmail.com","subject":"Re: [GSoC][PATCH 5/5] t: add test for git refs optimize subcommand","fromName":"shejialuo","fromEmail":"shejialuo@gmail.com","sentAt":"2025-08-26T15:18:18Z","receivedAt":"2025-08-26T15:18:21Z","isPatch":true,"sender":{"key":"shejialuo@gmail.com","avatar":"https://avatars.githubusercontent.com/u/56911263?v=4"},"body":"On Tue, Aug 26, 2025 at 01:06:45PM +0530, Meet Soni wrote:\n\n> diff --git a/t/t1463-refs-optimize.sh b/t/t1463-refs-optimize.sh\n> new file mode 100755\n> index 0000000000..c11c905d79\n> --- /dev/null\n> +++ b/t/t1463-refs-optimize.sh\n> @@ -0,0 +1,17 @@\n> +#!/bin/sh\n> +\n> +test_description='git refs optimize should not change the branch semantic\n> +\n> +This test runs git refs optimize and git show-ref and checks that the branch\n> +semantic is still the same.\n> +'\n\nWhen reading the description, I am wondering how this test runs `git\nrefs optimize` and `git show-ref` to achieve the goal. Should we simply\njust say we use \"pack-refs-tests.sh\" to ensure the compatibility with\nthe `git pack-refs`?\n\n> +\n> +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main\n> +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n> +GIT_TEST_DEFAULT_REF_FORMAT=files\n> +export GIT_TEST_DEFAULT_REF_FORMAT\n> +\n> +. ./test-lib.sh\n> +\n> +pack_refs='refs optimize'\n> +. \"$TEST_DIRECTORY\"/pack-refs-tests.sh\n> -- \n> 2.34.1\n> \n\nThanks,\nJialuo\n"},{"id":"525262","messageId":"CAPhwyn0r11owkcSLXDALfPjKe1QvexC0uH6F7B=vktwfAue53w@mail.gmail.com","threadId":"64034","inReplyTo":"aK3QOtQzUFsGvmyA@ArchLinux","subject":"Re: [GSoC][PATCH 5/5] t: add test for git refs optimize subcommand","fromName":"Meet Soni","fromEmail":"meetsoni3017@gmail.com","sentAt":"2025-08-31T06:20:32Z","receivedAt":"2025-08-31T06:20:44Z","isPatch":true,"sender":{"key":"meetsoni3017@gmail.com","avatar":"https://avatars.githubusercontent.com/u/92802561?v=4"},"body":"Thanks for the review, and apologies for missing your email earlier, I just saw\nyour comments today.\n\nOn Tue, 26 Aug 2025 at 20:48, shejialuo <shejialuo@gmail.com> wrote:\n>\n> On Tue, Aug 26, 2025 at 01:06:45PM +0530, Meet Soni wrote:\n>\n> > diff --git a/t/t1463-refs-optimize.sh b/t/t1463-refs-optimize.sh\n> > new file mode 100755\n> > index 0000000000..c11c905d79\n> > --- /dev/null\n> > +++ b/t/t1463-refs-optimize.sh\n> > @@ -0,0 +1,17 @@\n> > +#!/bin/sh\n> > +\n> > +test_description='git refs optimize should not change the branch semantic\n> > +\n> > +This test runs git refs optimize and git show-ref and checks that the branch\n> > +semantic is still the same.\n> > +'\n>\n> When reading the description, I am wondering how this test runs `git\n> refs optimize` and `git show-ref` to achieve the goal. Should we simply\n> just say we use \"pack-refs-tests.sh\" to ensure the compatibility with\n> the `git pack-refs`?\n>\nYou're right that the current description is too tied to implementation details\n(git show-ref). The intent of this test is to ensure that git refs optimize\ndoes not change branch semantics, similar to the existing pack-refs tests.\n\nI'll update the description to focus on the behavior being verified, not the\nspecific commands used.\n\n> > +\n> > +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main\n> > +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\n> > +GIT_TEST_DEFAULT_REF_FORMAT=files\n> > +export GIT_TEST_DEFAULT_REF_FORMAT\n> > +\n> > +. ./test-lib.sh\n> > +\n> > +pack_refs='refs optimize'\n> > +. \"$TEST_DIRECTORY\"/pack-refs-tests.sh\n> > --\n> > 2.34.1\n> >\n>\n> Thanks,\n> Jialuo\n\nThanks,\nMeet\n"},{"id":"525311","messageId":"aLbEWSHUotkmSiCq@pks.im","threadId":"64034","inReplyTo":"20250826073645.1074397-2-meetsoni3017@gmail.com","subject":"Re: [GSoC][PATCH 1/5] builtin/pack-refs: factor out core logic into a helper","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-09-02T10:18:01Z","receivedAt":"2025-09-02T10:18:09Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Aug 26, 2025 at 01:06:41PM +0530, Meet Soni wrote:\n> The implementation of `git pack-refs` is monolithic within\n> `cmd_pack_refs()`, making it impossible to share its logic with other\n> commands. To enable code reuse for the upcoming `git refs optimize`\n> subcommand, refactor the core logic into a shared helper function.\n> \n> Introduce a new `pack-refs.h` header to define the public interface\n> for this shared logic. It contains the declaration for a new helper\n> function, `pack_refs_core()`, and a macro for the common usage\n> options.\n> \n> Move the option parsing and packing logic from `cmd_pack_refs()` into a\n> new helper function named `pack_refs_core()`. This helper is made\n> generic by accepting the command's usage string as a parameter.\n> \n> The original `cmd_pack_refs()` is simplified to a thin wrapper that\n> is only responsible for defining its specific usage array and calling\n> the shared helper.\n> \n> Mentored-by: Patrick Steinhardt <ps@pks.im>\n> Mentored-by: shejialuo <shejialuo@gmail.com>\n> Signed-off-by: Meet Soni <meetsoni3017@gmail.com>\n> ---\n>  builtin/pack-refs.c | 31 ++++++++++++++++++++-----------\n>  pack-refs.h         | 22 ++++++++++++++++++++++\n>  2 files changed, 42 insertions(+), 11 deletions(-)\n>  create mode 100644 pack-refs.h\n\nShouldn't that header live in \"builtin/pack-refs.h\"? Makes it way more\nobvious that it exposes functions from \"builtin/pack-refs.c\".\n\n> diff --git a/pack-refs.h b/pack-refs.h\n> new file mode 100644\n> index 0000000000..ba51d154e3\n> --- /dev/null\n> +++ b/pack-refs.h\n> @@ -0,0 +1,22 @@\n> +#ifndef PACK_REFS_H\n> +#define PACK_REFS_H\n> +\n> +struct repository;\n\nLet's add a newline here.\n\n> +/*\n> + * Shared usage string for options common to git-pack-refs(1)\n> + * and git-refs-optimize(1). The command-specific part (e.g., \"git refs optimize \")\n> + * must be prepended by the caller.\n> + */\n> +#define PACK_REFS_OPTS \\\n> +\t\"[--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]\"\n> +\n> +/*\n> + * The core logic for pack-refs and its clones\n\nAnd a dot after to terminate the sentence.\n\n> + */\n> +int pack_refs_core(int argc,\n> +\t\t   const char **argv,\n> +\t\t   const char *prefix,\n> +\t\t   struct repository *repo,\n> +\t\t   const char * const *usage_opts);\n> +\n> +#endif /* PACK_REFS_H */\n\nPatrick\n"},{"id":"525312","messageId":"aLbEX-f8LGEFO13C@pks.im","threadId":"64034","inReplyTo":"20250826073645.1074397-4-meetsoni3017@gmail.com","subject":"Re: [GSoC][PATCH 3/5] builtin/refs: add optimize subcommand","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-09-02T10:18:07Z","receivedAt":"2025-09-02T10:18:12Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Aug 26, 2025 at 01:06:43PM +0530, Meet Soni wrote:\n> diff --git a/Documentation/git-refs.adoc b/Documentation/git-refs.adoc\n> index e608980711..121a2fbeff 100644\n> --- a/Documentation/git-refs.adoc\n> +++ b/Documentation/git-refs.adoc\n> @@ -18,6 +18,7 @@ git refs list [--count=<count>] [--shell|--perl|--python|--tcl]\n>  \t\t   [--contains[=<object>]] [--no-contains[=<object>]]\n>  \t\t   [(--exclude=<pattern>)...] [--start-after=<marker>]\n>  \t\t   [ --stdin | <pattern>... ]\n> +git refs optimize [--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]\n>  \n>  DESCRIPTION\n>  -----------\n> @@ -38,6 +39,11 @@ list::\n>  \tformatting, and sorting. This subcommand is an alias for\n>  \tlinkgit:git-for-each-ref[1] and offers identical functionality.\n>  \n> +optimize::\n> +        Pack references into a single file to improve repository performance\n> +        and reduce storage usage. This subcommand is an alias for\n> +        linkgit:git-pack-refs[1] and offers identical functionality.\n\nThis feels way too specific to the \"files\" backend. We do pack\nreferences there, but with the \"reftable\" backend we don't. Furthermore,\nthere is no guarantee that we'll only have a single file after\noptimizing the store with either of the backends.\n\nSo this should be rephrased to become agnostic of the actual backend\nthat is in use. Maybe just say something like \"Optimizes references to\nimprove repository performance and reduce disk usage.\"\n\nPatrick\n"},{"id":"525313","messageId":"aLbEZXusJEM9hohP@pks.im","threadId":"64034","inReplyTo":"20250826073645.1074397-6-meetsoni3017@gmail.com","subject":"Re: [GSoC][PATCH 5/5] t: add test for git refs optimize subcommand","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-09-02T10:18:13Z","receivedAt":"2025-09-02T10:18:18Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Aug 26, 2025 at 01:06:45PM +0530, Meet Soni wrote:\n> diff --git a/t/meson.build b/t/meson.build\n> index daf01fb5d0..48f83e12a7 100644\n> --- a/t/meson.build\n> +++ b/t/meson.build\n> @@ -210,6 +210,7 @@ integration_tests = [\n>    't1451-fsck-buffer.sh',\n>    't1460-refs-migrate.sh',\n>    't1461-refs-list.sh',\n> +  't1463-refs-optimize.sh',\n\nWhat happened to t1462? Is this due to the parallel patch series that\nintroduces `git refs exists`?\n\nPatrick\n"},{"id":"525386","messageId":"CAPhwyn1qm3CmYmupEdCzisdAC_uteWeBN05oZk0dqdPCty34yw@mail.gmail.com","threadId":"64034","inReplyTo":"aLbEWSHUotkmSiCq@pks.im","subject":"Re: [GSoC][PATCH 1/5] builtin/pack-refs: factor out core logic into a helper","fromName":"Meet Soni","fromEmail":"meetsoni3017@gmail.com","sentAt":"2025-09-03T03:56:37Z","receivedAt":"2025-09-03T03:56:50Z","isPatch":true,"sender":{"key":"meetsoni3017@gmail.com","avatar":"https://avatars.githubusercontent.com/u/92802561?v=4"},"body":"On Tue, 2 Sept 2025 at 15:48, Patrick Steinhardt <ps@pks.im> wrote:\n>\n> On Tue, Aug 26, 2025 at 01:06:41PM +0530, Meet Soni wrote:\n> > The implementation of `git pack-refs` is monolithic within\n> > `cmd_pack_refs()`, making it impossible to share its logic with other\n> > commands. To enable code reuse for the upcoming `git refs optimize`\n> > subcommand, refactor the core logic into a shared helper function.\n> >\n> > Introduce a new `pack-refs.h` header to define the public interface\n> > for this shared logic. It contains the declaration for a new helper\n> > function, `pack_refs_core()`, and a macro for the common usage\n> > options.\n> >\n> > Move the option parsing and packing logic from `cmd_pack_refs()` into a\n> > new helper function named `pack_refs_core()`. This helper is made\n> > generic by accepting the command's usage string as a parameter.\n> >\n> > The original `cmd_pack_refs()` is simplified to a thin wrapper that\n> > is only responsible for defining its specific usage array and calling\n> > the shared helper.\n> >\n> > Mentored-by: Patrick Steinhardt <ps@pks.im>\n> > Mentored-by: shejialuo <shejialuo@gmail.com>\n> > Signed-off-by: Meet Soni <meetsoni3017@gmail.com>\n> > ---\n> >  builtin/pack-refs.c | 31 ++++++++++++++++++++-----------\n> >  pack-refs.h         | 22 ++++++++++++++++++++++\n> >  2 files changed, 42 insertions(+), 11 deletions(-)\n> >  create mode 100644 pack-refs.h\n>\n> Shouldn't that header live in \"builtin/pack-refs.h\"? Makes it way more\n> obvious that it exposes functions from \"builtin/pack-refs.c\".\n>\nI couldn't find any header files in the builtin/ directory. Also, since we\nplaced the for-each-ref.h file in the root directory in our previous series, I\ndecided to do the same here.\n\n> > diff --git a/pack-refs.h b/pack-refs.h\n> > new file mode 100644\n> > index 0000000000..ba51d154e3\n> > --- /dev/null\n> > +++ b/pack-refs.h\n> > @@ -0,0 +1,22 @@\n> > +#ifndef PACK_REFS_H\n> > +#define PACK_REFS_H\n> > +\n> > +struct repository;\n>\n> Let's add a newline here.\n>\n> > +/*\n> > + * Shared usage string for options common to git-pack-refs(1)\n> > + * and git-refs-optimize(1). The command-specific part (e.g., \"git refs optimize \")\n> > + * must be prepended by the caller.\n> > + */\n> > +#define PACK_REFS_OPTS \\\n> > +     \"[--all] [--no-prune] [--auto] [--include <pattern>] [--exclude <pattern>]\"\n> > +\n> > +/*\n> > + * The core logic for pack-refs and its clones\n>\n> And a dot after to terminate the sentence.\n>\n> > + */\n> > +int pack_refs_core(int argc,\n> > +                const char **argv,\n> > +                const char *prefix,\n> > +                struct repository *repo,\n> > +                const char * const *usage_opts);\n> > +\n> > +#endif /* PACK_REFS_H */\n>\n> Patrick\n\nThanks\nMeet\n"},{"id":"525387","messageId":"CAPhwyn0p6TFp5nhGBVL9eBrE809HYdWKh=nHbY5Lf0HboDLSoQ@mail.gmail.com","threadId":"64034","inReplyTo":"aLbEZXusJEM9hohP@pks.im","subject":"Re: [GSoC][PATCH 5/5] t: add test for git refs optimize subcommand","fromName":"Meet Soni","fromEmail":"meetsoni3017@gmail.com","sentAt":"2025-09-03T03:58:20Z","receivedAt":"2025-09-03T03:58:31Z","isPatch":true,"sender":{"key":"meetsoni3017@gmail.com","avatar":"https://avatars.githubusercontent.com/u/92802561?v=4"},"body":"On Tue, 2 Sept 2025 at 15:48, Patrick Steinhardt <ps@pks.im> wrote:\n>\n> On Tue, Aug 26, 2025 at 01:06:45PM +0530, Meet Soni wrote:\n> > diff --git a/t/meson.build b/t/meson.build\n> > index daf01fb5d0..48f83e12a7 100644\n> > --- a/t/meson.build\n> > +++ b/t/meson.build\n> > @@ -210,6 +210,7 @@ integration_tests = [\n> >    't1451-fsck-buffer.sh',\n> >    't1460-refs-migrate.sh',\n> >    't1461-refs-list.sh',\n> > +  't1463-refs-optimize.sh',\n>\n> What happened to t1462? Is this due to the parallel patch series that\n> introduces `git refs exists`?\nYes, t1462-refs-exists.sh\n>\n> Patrick\n"},{"id":"525388","messageId":"aLfF-GWlp3ESnSU-@pks.im","threadId":"64034","inReplyTo":"CAPhwyn1qm3CmYmupEdCzisdAC_uteWeBN05oZk0dqdPCty34yw@mail.gmail.com","subject":"Re: [GSoC][PATCH 1/5] builtin/pack-refs: factor out core logic into a helper","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-09-03T04:37:12Z","receivedAt":"2025-09-03T04:37:19Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Wed, Sep 03, 2025 at 09:26:37AM +0530, Meet Soni wrote:\n> On Tue, 2 Sept 2025 at 15:48, Patrick Steinhardt <ps@pks.im> wrote:\n> >\n> > On Tue, Aug 26, 2025 at 01:06:41PM +0530, Meet Soni wrote:\n> > > The implementation of `git pack-refs` is monolithic within\n> > > `cmd_pack_refs()`, making it impossible to share its logic with other\n> > > commands. To enable code reuse for the upcoming `git refs optimize`\n> > > subcommand, refactor the core logic into a shared helper function.\n> > >\n> > > Introduce a new `pack-refs.h` header to define the public interface\n> > > for this shared logic. It contains the declaration for a new helper\n> > > function, `pack_refs_core()`, and a macro for the common usage\n> > > options.\n> > >\n> > > Move the option parsing and packing logic from `cmd_pack_refs()` into a\n> > > new helper function named `pack_refs_core()`. This helper is made\n> > > generic by accepting the command's usage string as a parameter.\n> > >\n> > > The original `cmd_pack_refs()` is simplified to a thin wrapper that\n> > > is only responsible for defining its specific usage array and calling\n> > > the shared helper.\n> > >\n> > > Mentored-by: Patrick Steinhardt <ps@pks.im>\n> > > Mentored-by: shejialuo <shejialuo@gmail.com>\n> > > Signed-off-by: Meet Soni <meetsoni3017@gmail.com>\n> > > ---\n> > >  builtin/pack-refs.c | 31 ++++++++++++++++++++-----------\n> > >  pack-refs.h         | 22 ++++++++++++++++++++++\n> > >  2 files changed, 42 insertions(+), 11 deletions(-)\n> > >  create mode 100644 pack-refs.h\n> >\n> > Shouldn't that header live in \"builtin/pack-refs.h\"? Makes it way more\n> > obvious that it exposes functions from \"builtin/pack-refs.c\".\n> \n> I couldn't find any header files in the builtin/ directory. Also, since we\n> placed the for-each-ref.h file in the root directory in our previous series, I\n> decided to do the same here.\n\nHm. Honestly, I'd much rather also move \"for-each-ref.h\" into\n\"builtin/\", as well. The logic is not part of libgit.a and specific to\nthe builtins, so I think it's preferable to have it in that directory.\n\nPatrick\n"},{"id":"525394","messageId":"xmqq8qiwgl9j.fsf@gitster.g","threadId":"64034","inReplyTo":"aLbEWSHUotkmSiCq@pks.im","subject":"Re: [GSoC][PATCH 1/5] builtin/pack-refs: factor out core logic into a helper","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-09-03T05:25:44Z","receivedAt":"2025-09-03T05:25:47Z","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>>  builtin/pack-refs.c | 31 ++++++++++++++++++++-----------\n>>  pack-refs.h         | 22 ++++++++++++++++++++++\n>>  2 files changed, 42 insertions(+), 11 deletions(-)\n>>  create mode 100644 pack-refs.h\n>\n> Shouldn't that header live in \"builtin/pack-refs.h\"? Makes it way more\n> obvious that it exposes functions from \"builtin/pack-refs.c\".\n\nThere shouldn't be any *.h files in builtin/.  since the top-level\nis where the library-ish reusable things live, so that they can\neventually be used by more than one *.c files in builtin/ and also\nby other *.c files outside builtin.\n\n"},{"id":"525397","messageId":"aLfZflWT4618ptCA@pks.im","threadId":"64034","inReplyTo":"xmqq8qiwgl9j.fsf@gitster.g","subject":"Re: [GSoC][PATCH 1/5] builtin/pack-refs: factor out core logic into a helper","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2025-09-03T06:00:30Z","receivedAt":"2025-09-03T06:00:36Z","isPatch":true,"sender":{"key":"ps@pks.im","avatar":"https://avatars.githubusercontent.com/u/4056630?v=4"},"body":"On Tue, Sep 02, 2025 at 10:25:44PM -0700, Junio C Hamano wrote:\n> Patrick Steinhardt <ps@pks.im> writes:\n> \n> >>  builtin/pack-refs.c | 31 ++++++++++++++++++++-----------\n> >>  pack-refs.h         | 22 ++++++++++++++++++++++\n> >>  2 files changed, 42 insertions(+), 11 deletions(-)\n> >>  create mode 100644 pack-refs.h\n> >\n> > Shouldn't that header live in \"builtin/pack-refs.h\"? Makes it way more\n> > obvious that it exposes functions from \"builtin/pack-refs.c\".\n> \n> There shouldn't be any *.h files in builtin/.  since the top-level\n> is where the library-ish reusable things live, so that they can\n> eventually be used by more than one *.c files in builtin/ and also\n> by other *.c files outside builtin.\n\nHm, okay. I still find it puzzling if the header file for\n\"builtin/pack-refs.c\" sits in \"pack-refs.h\" as it makes it very hard to\nconnect these two. How would you reconcile that? By moving the shared\nlogic into (non-\"builtin/) \"pack-refs.c\"?\n\nPatrick\n"},{"id":"525453","messageId":"xmqqikhzfldi.fsf@gitster.g","threadId":"64034","inReplyTo":"aLfZflWT4618ptCA@pks.im","subject":"Re: [GSoC][PATCH 1/5] builtin/pack-refs: factor out core logic into a helper","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-09-03T18:20:57Z","receivedAt":"2025-09-03T18:20:59Z","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> Hm, okay. I still find it puzzling if the header file for\n> \"builtin/pack-refs.c\" sits in \"pack-refs.h\" as it makes it very hard to\n> connect these two. How would you reconcile that? By moving the shared\n> logic into (non-\"builtin/) \"pack-refs.c\"?\n\nYeah, if that is not happening, then the change is only half done, I\nwould think.\n\nThanks.\n"}]}