Skip to content

Commit 8e0a1ec

Browse files
pks-tgitster
authored andcommitted
builtin/maintenance: introduce "reflog-expire" task
By default, git-maintenance(1) uses the "gc" task to ensure that the repository is well-maintained. This can be changed, for example by either explicitly configuring which tasks should be enabled or by using the "incremental" maintenance strategy. If so, git-maintenance(1) does not know to expire reflog entries, which is a subtask that git-gc(1) knows to perform for the user. Consequently, the reflog will grow indefinitely unless the user manually trims it. Introduce a new "reflog-expire" task that plugs this gap: - When running the task directly, then we simply execute `git reflog expire --all`, which is the same as git-gc(1). - When running git-maintenance(1) with the `--auto` flag, then we only run the task in case the "HEAD" reflog has at least N reflog entries that would be discarded. By default, N is set to 100, but this can be configured via "maintenance.reflog-expire.auto". When a negative integer has been provided we always expire entries, zero causes us to never expire entries, and a positive value specifies how many entries need to exist before we consider pruning the entries. Note that the condition for the `--auto` flags is merely a heuristic and optimized for being fast. This is because `git maintenance run --auto` will be executed quite regularly, so scanning through all reflogs would likely be too expensive in many repositories. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 3fef24a commit 8e0a1ec

File tree

4 files changed

+81
-0
lines changed

4 files changed

+81
-0
lines changed

Documentation/config/maintenance.adoc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,12 @@ maintenance.incremental-repack.auto::
6969
Otherwise, a positive value implies the command should run when the
7070
number of pack-files not in the multi-pack-index is at least the value
7171
of `maintenance.incremental-repack.auto`. The default value is 10.
72+
73+
maintenance.reflog-expire.auto::
74+
This integer config option controls how often the `reflog-expire` task
75+
should be run as part of `git maintenance run --auto`. If zero, then
76+
the `reflog-expire` task will not run with the `--auto` option. A
77+
negative value will force the task to run every time. Otherwise, a
78+
positive value implies the command should run when the number of
79+
expired reflog entries in the "HEAD" reflog is at least the value of
80+
`maintenance.loose-objects.auto`. The default value is 100.

Documentation/git-maintenance.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,10 @@ pack-refs::
158158
need to iterate across many references. See linkgit:git-pack-refs[1]
159159
for more information.
160160

161+
reflog-expire::
162+
The `reflog-expire` task deletes any entries in the reflog older than the
163+
expiry threshold. See linkgit:git-reflog[1] for more information.
164+
161165
OPTIONS
162166
-------
163167
--auto::

builtin/gc.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "pack.h"
3434
#include "pack-objects.h"
3535
#include "path.h"
36+
#include "reflog.h"
3637
#include "blob.h"
3738
#include "tree.h"
3839
#include "promisor-remote.h"
@@ -285,6 +286,49 @@ static int maintenance_task_pack_refs(struct maintenance_run_opts *opts,
285286
return run_command(&cmd);
286287
}
287288

289+
struct count_reflog_entries_data {
290+
struct expire_reflog_policy_cb policy;
291+
size_t count;
292+
size_t limit;
293+
};
294+
295+
static int count_reflog_entries(struct object_id *old_oid, struct object_id *new_oid,
296+
const char *committer, timestamp_t timestamp,
297+
int tz, const char *msg, void *cb_data)
298+
{
299+
struct count_reflog_entries_data *data = cb_data;
300+
if (should_expire_reflog_ent(old_oid, new_oid, committer, timestamp, tz, msg, &data->policy))
301+
data->count++;
302+
return data->count >= data->limit;
303+
}
304+
305+
static int reflog_expire_condition(struct gc_config *cfg UNUSED)
306+
{
307+
timestamp_t now = time(NULL);
308+
struct count_reflog_entries_data data = {
309+
.policy = {
310+
.opts = REFLOG_EXPIRE_OPTIONS_INIT(now),
311+
},
312+
};
313+
int limit = 100;
314+
315+
git_config_get_int("maintenance.reflog-expire.auto", &limit);
316+
if (!limit)
317+
return 0;
318+
if (limit < 0)
319+
return 1;
320+
data.limit = limit;
321+
322+
repo_config(the_repository, reflog_expire_config, &data.policy.opts);
323+
324+
reflog_expire_options_set_refname(&data.policy.opts, "HEAD");
325+
refs_for_each_reflog_ent(get_main_ref_store(the_repository), "HEAD",
326+
count_reflog_entries, &data);
327+
328+
reflog_expiry_cleanup(&data.policy);
329+
return data.count >= data.limit;
330+
}
331+
288332
static int maintenance_task_reflog_expire(struct maintenance_run_opts *opts UNUSED,
289333
struct gc_config *cfg UNUSED)
290334
{
@@ -1383,6 +1427,7 @@ enum maintenance_task_label {
13831427
TASK_GC,
13841428
TASK_COMMIT_GRAPH,
13851429
TASK_PACK_REFS,
1430+
TASK_REFLOG_EXPIRE,
13861431

13871432
/* Leave as final value */
13881433
TASK__COUNT
@@ -1419,6 +1464,11 @@ static struct maintenance_task tasks[] = {
14191464
maintenance_task_pack_refs,
14201465
pack_refs_condition,
14211466
},
1467+
[TASK_REFLOG_EXPIRE] = {
1468+
"reflog-expire",
1469+
maintenance_task_reflog_expire,
1470+
reflog_expire_condition,
1471+
},
14221472
};
14231473

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

t/t7900-maintenance.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,24 @@ test_expect_success 'pack-refs task' '
447447
test_subcommand git pack-refs --all --prune <pack-refs.txt
448448
'
449449

450+
test_expect_success 'reflog-expire task' '
451+
GIT_TRACE2_EVENT="$(pwd)/reflog-expire.txt" \
452+
git maintenance run --task=reflog-expire &&
453+
test_subcommand git reflog expire --all <reflog-expire.txt
454+
'
455+
456+
test_expect_success 'reflog-expire task --auto only packs when exceeding limits' '
457+
git reflog expire --all --expire=now &&
458+
test_commit reflog-one &&
459+
test_commit reflog-two &&
460+
GIT_TRACE2_EVENT="$(pwd)/reflog-expire-auto.txt" \
461+
git -c maintenance.reflog-expire.auto=3 maintenance run --auto --task=reflog-expire &&
462+
test_subcommand ! git reflog expire --all <reflog-expire-auto.txt &&
463+
GIT_TRACE2_EVENT="$(pwd)/reflog-expire-auto.txt" \
464+
git -c maintenance.reflog-expire.auto=2 maintenance run --auto --task=reflog-expire &&
465+
test_subcommand git reflog expire --all <reflog-expire-auto.txt
466+
'
467+
450468
test_expect_success '--auto and --schedule incompatible' '
451469
test_must_fail git maintenance run --auto --schedule=daily 2>err &&
452470
test_grep "at most one" err

0 commit comments

Comments
 (0)