Skip to content

Commit 41abfe1

Browse files
derrickstoleegitster
authored andcommitted
maintenance: add pack-refs task
It is valuable to collect loose refs into a more compressed form. This is typically the packed-refs file, although this could be the reftable in the future. Having packed refs can be extremely valuable in repos with many tags or remote branches that are not modified by the local user, but still are necessary for other queries. For instance, with many exploded refs, commands such as git describe --tags --exact-match HEAD can be very slow (multiple seconds). This command in particular is used by terminal prompts to show when a detatched HEAD is pointing to an existing tag, so having it be slow causes significant delays for users. Add a new 'pack-refs' maintenance task. It runs 'git pack-refs --all --prune' to move loose refs into a packed form. For now, that is the packed-refs file, but could adjust to other file formats in the future. This is the first of several sub-tasks of the 'gc' task that could be extracted to their own tasks. In this process, we should not change the behavior of the 'gc' task since that remains the default way to keep repositories maintained. Creating a new task for one of these sub-tasks only provides more customization options for those choosing to not use the 'gc' task. It is certainly possible to have both the 'gc' and 'pack-refs' tasks enabled and run regularly. While they may repeat effort, they do not conflict in a destructive way. The 'auto_condition' function pointer is left NULL for now. We could extend this in the future to have a condition check if pack-refs should be run during 'git maintenance run --auto'. Signed-off-by: Derrick Stolee <[email protected]> Reviewed-by: Taylor Blau <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent fb7fa4a commit 41abfe1

File tree

3 files changed

+35
-4
lines changed

3 files changed

+35
-4
lines changed

Documentation/git-maintenance.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,12 @@ incremental-repack::
145145
which is a special case that attempts to repack all pack-files
146146
into a single pack-file.
147147

148+
pack-refs::
149+
The `pack-refs` task collects the loose reference files and
150+
collects them into a single file. This speeds up operations that
151+
need to iterate across many references. See linkgit:git-pack-refs[1]
152+
for more information.
153+
148154
OPTIONS
149155
-------
150156
--auto::

builtin/gc.c

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ static const char *prune_worktrees_expire = "3.months.ago";
5454
static unsigned long big_pack_threshold;
5555
static unsigned long max_delta_cache_size = DEFAULT_DELTA_CACHE_SIZE;
5656

57-
static struct strvec pack_refs_cmd = STRVEC_INIT;
5857
static struct strvec reflog = STRVEC_INIT;
5958
static struct strvec repack = STRVEC_INIT;
6059
static struct strvec prune = STRVEC_INIT;
@@ -163,6 +162,15 @@ static void gc_config(void)
163162
git_config(git_default_config, NULL);
164163
}
165164

165+
struct maintenance_run_opts;
166+
static int maintenance_task_pack_refs(MAYBE_UNUSED struct maintenance_run_opts *opts)
167+
{
168+
struct strvec pack_refs_cmd = STRVEC_INIT;
169+
strvec_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
170+
171+
return run_command_v_opt(pack_refs_cmd.v, RUN_GIT_CMD);
172+
}
173+
166174
static int too_many_loose_objects(void)
167175
{
168176
/*
@@ -518,8 +526,8 @@ static void gc_before_repack(void)
518526
if (done++)
519527
return;
520528

521-
if (pack_refs && run_command_v_opt(pack_refs_cmd.v, RUN_GIT_CMD))
522-
die(FAILED_RUN, pack_refs_cmd.v[0]);
529+
if (pack_refs && maintenance_task_pack_refs(NULL))
530+
die(FAILED_RUN, "pack-refs");
523531

524532
if (prune_reflogs && run_command_v_opt(reflog.v, RUN_GIT_CMD))
525533
die(FAILED_RUN, reflog.v[0]);
@@ -556,7 +564,6 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
556564
if (argc == 2 && !strcmp(argv[1], "-h"))
557565
usage_with_options(builtin_gc_usage, builtin_gc_options);
558566

559-
strvec_pushl(&pack_refs_cmd, "pack-refs", "--all", "--prune", NULL);
560567
strvec_pushl(&reflog, "reflog", "expire", "--all", NULL);
561568
strvec_pushl(&repack, "repack", "-d", "-l", NULL);
562569
strvec_pushl(&prune, "prune", "--expire", NULL);
@@ -1224,6 +1231,7 @@ enum maintenance_task_label {
12241231
TASK_INCREMENTAL_REPACK,
12251232
TASK_GC,
12261233
TASK_COMMIT_GRAPH,
1234+
TASK_PACK_REFS,
12271235

12281236
/* Leave as final value */
12291237
TASK__COUNT
@@ -1255,6 +1263,11 @@ static struct maintenance_task tasks[] = {
12551263
maintenance_task_commit_graph,
12561264
should_write_commit_graph,
12571265
},
1266+
[TASK_PACK_REFS] = {
1267+
"pack-refs",
1268+
maintenance_task_pack_refs,
1269+
NULL,
1270+
},
12581271
};
12591272

12601273
static int compare_tasks_by_selection(const void *a_, const void *b_)

t/t7900-maintenance.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,18 @@ test_expect_success 'maintenance.incremental-repack.auto' '
343343
test_subcommand git multi-pack-index write --no-progress <trace-B
344344
'
345345

346+
test_expect_success 'pack-refs task' '
347+
for n in $(test_seq 1 5)
348+
do
349+
git branch -f to-pack/$n HEAD || return 1
350+
done &&
351+
GIT_TRACE2_EVENT="$(pwd)/pack-refs.txt" \
352+
git maintenance run --task=pack-refs &&
353+
ls .git/refs/heads/ >after &&
354+
test_must_be_empty after &&
355+
test_subcommand git pack-refs --all --prune <pack-refs.txt
356+
'
357+
346358
test_expect_success '--auto and --schedule incompatible' '
347359
test_must_fail git maintenance run --auto --schedule=daily 2>err &&
348360
test_i18ngrep "at most one" err

0 commit comments

Comments
 (0)