Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
* whitespace=!indent,trail,space
* whitespace=trail,space
*.[ch] whitespace=indent,trail,space diff=cpp
*.sh whitespace=indent,trail,space text eol=lf
*.perl text eol=lf diff=perl
Expand Down
19 changes: 19 additions & 0 deletions Documentation/RelNotes/2.53.0.adoc
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
Git v2.53 Release Notes
=======================

UI, Workflows & Features
------------------------

* "git maintenance" command learned "is-needed" subcommand to tell if
it is necessary to perform various maintenance tasks.


Performance, Internal Implementation, Development Support etc.
--------------------------------------------------------------

Expand All @@ -10,3 +17,15 @@ Performance, Internal Implementation, Development Support etc.
* Some ref backend storage can hold not just the object name of an
annotated tag, but the object name of the object the tag points at.
The code to handle this information has been streamlined.

* As "git diff --quiet" only cares about the existence of any
changes, disable rename/copy detection to skip more expensive
processing whose result will be discarded anyway.


Fixes since v2.51
-----------------

* Ever since we added whitespace rules for this project, we misspelt
an entry, which has been corrected.
(merge 358e94dc70 jc/gitattributes-whitespace-no-indent-fix later to maint).
13 changes: 13 additions & 0 deletions Documentation/git-maintenance.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ SYNOPSIS
'git maintenance' run [<options>]
'git maintenance' start [--scheduler=<scheduler>]
'git maintenance' (stop|register|unregister) [<options>]
'git maintenance' is-needed [<options>]


DESCRIPTION
Expand Down Expand Up @@ -84,6 +85,16 @@ The `unregister` subcommand will report an error if the current repository
is not already registered. Use the `--force` option to return success even
when the current repository is not registered.

is-needed::
Check whether maintenance needs to be run without actually running it.
Exits with a 0 status code if maintenance needs to be run, 1 otherwise.
Ideally used with the '--auto' flag.
+
If one or more `--task` options are specified, then those tasks are checked
in that order. Otherwise, the tasks are determined by which
`maintenance.<task>.enabled` config options are true. By default, only
`maintenance.gc.enabled` is true.

TASKS
-----

Expand Down Expand Up @@ -183,6 +194,8 @@ OPTIONS
in the `gc.auto` config setting, or when the number of pack-files
exceeds the `gc.autoPackLimit` config setting. Not compatible with
the `--schedule` option.
When combined with the `is-needed` subcommand, check if the required
thresholds are met without actually running maintenance.

--schedule::
When combined with the `run` subcommand, run maintenance tasks
Expand Down
93 changes: 83 additions & 10 deletions builtin/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
#include "reflog.h"
#include "repack.h"
#include "rerere.h"
#include "revision.h"
#include "blob.h"
#include "tree.h"
#include "promisor-remote.h"
Expand Down Expand Up @@ -286,12 +287,26 @@ static void maintenance_run_opts_release(struct maintenance_run_opts *opts)

static int pack_refs_condition(UNUSED struct gc_config *cfg)
{
/*
* The auto-repacking logic for refs is handled by the ref backends and
* exposed via `git pack-refs --auto`. We thus always return truish
* here and let the backend decide for us.
*/
return 1;
struct string_list included_refs = STRING_LIST_INIT_NODUP;
struct ref_exclusions excludes = REF_EXCLUSIONS_INIT;
struct refs_optimize_opts optimize_opts = {
.exclusions = &excludes,
.includes = &included_refs,
.flags = REFS_OPTIMIZE_PRUNE | REFS_OPTIMIZE_AUTO,
};
bool required;

/* Check for all refs, similar to 'git refs optimize --all'. */
string_list_append(optimize_opts.includes, "*");

if (refs_optimize_required(get_main_ref_store(the_repository),
&optimize_opts, &required))
return 0;

clear_ref_exclusions(&excludes);
string_list_clear(&included_refs, 0);

return required;
}

static int maintenance_task_pack_refs(struct maintenance_run_opts *opts,
Expand Down Expand Up @@ -1095,9 +1110,6 @@ static int maintenance_opt_schedule(const struct option *opt, const char *arg,
return 0;
}

/* Remember to update object flag allocation in object.h */
#define SEEN (1u<<0)

struct cg_auto_data {
int num_not_in_graph;
int limit;
Expand Down Expand Up @@ -3444,7 +3456,67 @@ static int maintenance_stop(int argc, const char **argv, const char *prefix,
return update_background_schedule(NULL, 0);
}

static const char * const builtin_maintenance_usage[] = {
static const char *const builtin_maintenance_is_needed_usage[] = {
"git maintenance is-needed [--task=<task>] [--schedule]",
NULL
};

static int maintenance_is_needed(int argc, const char **argv, const char *prefix,
struct repository *repo UNUSED)
{
struct maintenance_run_opts opts = MAINTENANCE_RUN_OPTS_INIT;
struct string_list selected_tasks = STRING_LIST_INIT_DUP;
struct gc_config cfg = GC_CONFIG_INIT;
struct option options[] = {
OPT_BOOL(0, "auto", &opts.auto_flag,
N_("run tasks based on the state of the repository")),
OPT_CALLBACK_F(0, "task", &selected_tasks, N_("task"),
N_("check a specific task"),
PARSE_OPT_NONEG, task_option_parse),
OPT_END()
};
bool is_needed = false;

argc = parse_options(argc, argv, prefix, options,
builtin_maintenance_is_needed_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (argc)
usage_with_options(builtin_maintenance_is_needed_usage, options);

gc_config(&cfg);
initialize_task_config(&opts, &selected_tasks);

if (opts.auto_flag) {
for (size_t i = 0; i < opts.tasks_nr; i++) {
if (tasks[opts.tasks[i]].auto_condition &&
tasks[opts.tasks[i]].auto_condition(&cfg)) {
is_needed = true;
break;
}
}
} else {
/*
* When not using --auto we always require maintenance right now.
*
* TODO: this certainly is too eager, as some maintenance tasks may
* decide to not do anything because the data structures are already
* fully optimized. We may eventually want to extend the auto
* condition to also cover non-auto runs so that we can detect such
* cases.
*/
is_needed = true;
}

string_list_clear(&selected_tasks, 0);
maintenance_run_opts_release(&opts);
gc_config_release(&cfg);

if (is_needed)
return 0;
return 1;
}

static const char *const builtin_maintenance_usage[] = {
N_("git maintenance <subcommand> [<options>]"),
NULL,
};
Expand All @@ -3461,6 +3533,7 @@ int cmd_maintenance(int argc,
OPT_SUBCOMMAND("stop", &fn, maintenance_stop),
OPT_SUBCOMMAND("register", &fn, maintenance_register),
OPT_SUBCOMMAND("unregister", &fn, maintenance_unregister),
OPT_SUBCOMMAND("is-needed", &fn, maintenance_is_needed),
OPT_END(),
};

Expand Down
2 changes: 2 additions & 0 deletions diff.c
Original file line number Diff line number Diff line change
Expand Up @@ -4987,6 +4987,8 @@ void diff_setup_done(struct diff_options *options)
if (options->flags.quick) {
options->output_format = DIFF_FORMAT_NO_OUTPUT;
options->flags.exit_with_status = 1;
options->detect_rename = 0;
options->flags.find_copies_harder = 0;
}

/*
Expand Down
1 change: 0 additions & 1 deletion object.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,6 @@ void object_array_init(struct object_array *array);
* list-objects-filter.c: 21
* bloom.c: 2122
* builtin/fsck.c: 0--3
* builtin/gc.c: 0
* builtin/index-pack.c: 2021
* reflog.c: 10--12
* builtin/show-branch.c: 0-------------------------------------------26
Expand Down
7 changes: 7 additions & 0 deletions refs.c
Original file line number Diff line number Diff line change
Expand Up @@ -2318,6 +2318,13 @@ int refs_optimize(struct ref_store *refs, struct refs_optimize_opts *opts)
return refs->be->optimize(refs, opts);
}

int refs_optimize_required(struct ref_store *refs,
struct refs_optimize_opts *opts,
bool *required)
{
return refs->be->optimize_required(refs, opts, required);
}

int reference_get_peeled_oid(struct repository *repo,
const struct reference *ref,
struct object_id *peeled_oid)
Expand Down
7 changes: 7 additions & 0 deletions refs.h
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,13 @@ struct refs_optimize_opts {
*/
int refs_optimize(struct ref_store *refs, struct refs_optimize_opts *opts);

/*
* Check if refs backend can be optimized by calling 'refs_optimize'.
*/
int refs_optimize_required(struct ref_store *ref_store,
struct refs_optimize_opts *opts,
bool *required);

/*
* Setup reflog before using. Fill in err and return -1 on failure.
*/
Expand Down
13 changes: 13 additions & 0 deletions refs/debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,17 @@ static int debug_optimize(struct ref_store *ref_store, struct refs_optimize_opts
return res;
}

static int debug_optimize_required(struct ref_store *ref_store,
struct refs_optimize_opts *opts,
bool *required)
{
struct debug_ref_store *drefs = (struct debug_ref_store *)ref_store;
int res = drefs->refs->be->optimize_required(drefs->refs, opts, required);
trace_printf_key(&trace_refs, "optimize_required: %s, res: %d\n",
required ? "yes" : "no", res);
return res;
}

static int debug_rename_ref(struct ref_store *ref_store, const char *oldref,
const char *newref, const char *logmsg)
{
Expand Down Expand Up @@ -440,6 +451,8 @@ struct ref_storage_be refs_be_debug = {
.transaction_abort = debug_transaction_abort,

.optimize = debug_optimize,
.optimize_required = debug_optimize_required,

.rename_ref = debug_rename_ref,
.copy_ref = debug_copy_ref,

Expand Down
11 changes: 11 additions & 0 deletions refs/files-backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -1512,6 +1512,16 @@ static int files_optimize(struct ref_store *ref_store,
return 0;
}

static int files_optimize_required(struct ref_store *ref_store,
struct refs_optimize_opts *opts,
bool *required)
{
struct files_ref_store *refs = files_downcast(ref_store, REF_STORE_READ,
"optimize_required");
*required = should_pack_refs(refs, opts);
return 0;
}

/*
* People using contrib's git-new-workdir have .git/logs/refs ->
* /some/other/path/.git/logs/refs, and that may live on another device.
Expand Down Expand Up @@ -3982,6 +3992,7 @@ struct ref_storage_be refs_be_files = {
.transaction_abort = files_transaction_abort,

.optimize = files_optimize,
.optimize_required = files_optimize_required,
.rename_ref = files_rename_ref,
.copy_ref = files_copy_ref,

Expand Down
13 changes: 13 additions & 0 deletions refs/packed-backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -1784,6 +1784,17 @@ static int packed_optimize(struct ref_store *ref_store UNUSED,
return 0;
}

static int packed_optimize_required(struct ref_store *ref_store UNUSED,
struct refs_optimize_opts *opts UNUSED,
bool *required)
{
/*
* Packed refs are already optimized.
*/
*required = false;
return 0;
}

static struct ref_iterator *packed_reflog_iterator_begin(struct ref_store *ref_store UNUSED)
{
return empty_ref_iterator_begin();
Expand Down Expand Up @@ -2130,6 +2141,8 @@ struct ref_storage_be refs_be_packed = {
.transaction_abort = packed_transaction_abort,

.optimize = packed_optimize,
.optimize_required = packed_optimize_required,

.rename_ref = NULL,
.copy_ref = NULL,

Expand Down
6 changes: 6 additions & 0 deletions refs/refs-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,11 @@ typedef int ref_transaction_commit_fn(struct ref_store *refs,

typedef int optimize_fn(struct ref_store *ref_store,
struct refs_optimize_opts *opts);

typedef int optimize_required_fn(struct ref_store *ref_store,
struct refs_optimize_opts *opts,
bool *required);

typedef int rename_ref_fn(struct ref_store *ref_store,
const char *oldref, const char *newref,
const char *logmsg);
Expand Down Expand Up @@ -549,6 +554,7 @@ struct ref_storage_be {
ref_transaction_abort_fn *transaction_abort;

optimize_fn *optimize;
optimize_required_fn *optimize_required;
rename_ref_fn *rename_ref;
copy_ref_fn *copy_ref;

Expand Down
25 changes: 25 additions & 0 deletions refs/reftable-backend.c
Original file line number Diff line number Diff line change
Expand Up @@ -1733,6 +1733,29 @@ static int reftable_be_optimize(struct ref_store *ref_store,
return ret;
}

static int reftable_be_optimize_required(struct ref_store *ref_store,
struct refs_optimize_opts *opts,
bool *required)
{
struct reftable_ref_store *refs = reftable_be_downcast(ref_store, REF_STORE_READ,
"optimize_refs_required");
struct reftable_stack *stack;
bool use_heuristics = false;

if (refs->err)
return refs->err;

stack = refs->worktree_backend.stack;
if (!stack)
stack = refs->main_backend.stack;

if (opts->flags & REFS_OPTIMIZE_AUTO)
use_heuristics = true;

return reftable_stack_compaction_required(stack, use_heuristics,
required);
}

struct write_create_symref_arg {
struct reftable_ref_store *refs;
struct reftable_stack *stack;
Expand Down Expand Up @@ -2756,6 +2779,8 @@ struct ref_storage_be refs_be_reftable = {
.transaction_abort = reftable_be_transaction_abort,

.optimize = reftable_be_optimize,
.optimize_required = reftable_be_optimize_required,

.rename_ref = reftable_be_rename_ref,
.copy_ref = reftable_be_copy_ref,

Expand Down
11 changes: 11 additions & 0 deletions reftable/reftable-stack.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,17 @@ struct reftable_log_expiry_config {
int reftable_stack_compact_all(struct reftable_stack *st,
struct reftable_log_expiry_config *config);

/*
* Check if compaction is required.
*
* When `use_heuristics` is false, check if all tables can be compacted to a
* single table. If true, use heuristics to determine if the tables need to be
* compacted to maintain geometric progression.
*/
int reftable_stack_compaction_required(struct reftable_stack *st,
bool use_heuristics,
bool *required);

/* heuristically compact unbalanced table stack. */
int reftable_stack_auto_compact(struct reftable_stack *st);

Expand Down
Loading