From patchwork Fri Aug 28 15:45:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derrick Stolee via GitGitGadget X-Patchwork-Id: 11743237 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3FD8813B6 for ; Fri, 28 Aug 2020 15:45:47 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1FF5B20678 for ; Fri, 28 Aug 2020 15:45:47 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="uinY7JYb" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728301AbgH1Ppo (ORCPT ); Fri, 28 Aug 2020 11:45:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39490 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728227AbgH1PpY (ORCPT ); Fri, 28 Aug 2020 11:45:24 -0400 Received: from mail-wr1-x443.google.com (mail-wr1-x443.google.com [IPv6:2a00:1450:4864:20::443]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1F79CC061233 for ; Fri, 28 Aug 2020 08:45:24 -0700 (PDT) Received: by mail-wr1-x443.google.com with SMTP id y3so1725759wrl.4 for ; Fri, 28 Aug 2020 08:45:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=5lURrJo2phQFyTaCa9VzL15Edu5uwyU3aVspJO/+d8Q=; b=uinY7JYbaY5qhsJzxeD53kTjWzC4RQ5JhFQPuoEWRCZWaO/JrfKvo+K4jNGhtAyFz8 opuJsXlBVAuBEpNhO+HQlUlyWRuP7Gxn1ZE1CxyNDpv7uzVe/VVGTdqPzH5jRiZ6jyIZ ogbfEMqh+epX0raXZwRJgboD8YLD5+Vu+VirZLxFS+F3DrAu1FFkpKunA1fDN1uwDnIb 2jg/TOA52uQsRmjEh87mxzsOgiJS8WNUFt5IudULJHmwSdK+j6UM0xLved7b5EPVGGFj QYNdpwkroary8IipZDZa507zN+fyceFji0UAjJhOMnSguEbnvHnITQjsK/72778UwPBX Pzmg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=5lURrJo2phQFyTaCa9VzL15Edu5uwyU3aVspJO/+d8Q=; b=lHOvy/oW86QqDPctpUaPNNRrv53qkp7hSFAVtxZNdII0yc3y3xfXQA4lh7mbdZs/bs ciKdVbvOKAXbNbr0J19ufaoH6WpwCanbIE23atz9bD1yG5OBc50e9zQ2E5q7aNPkDl5C 3o6SsrmnQqO8jEkXZWi6asMoGc9AG6pBPzUpOC5IC+EvaWIQm+/CYqsFHw7k2DdsXoMu xhnXVXF3I0+NtQpoYrC02bUhrw2m5LWk6hJzcGu+zGHubSZDF8dN7DanrJcxG2Zirtr3 k277jZand4uXq11hZ5unzZYm4KrbONqHos2aDacevk+zutblHdZ4eMm8QplDthFSdB3y nLAg== X-Gm-Message-State: AOAM533XYvT6f+lDZatvW99q/AO3/CJEPZ83X0DN5y/2HDyU7lX7FG1p L57NQNF9JfHFv6M7k5QNdF1Oc+61BtA= X-Google-Smtp-Source: ABdhPJwWLAgN4fY2Il0NiBbHmUW5w4n07FynN/a2NjyuTyPKKC+ztHDnNMyJ5uBNXVfldCkQhV3k5g== X-Received: by 2002:adf:b602:: with SMTP id f2mr2010860wre.186.1598629519588; Fri, 28 Aug 2020 08:45:19 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id l7sm2820854wmh.15.2020.08.28.08.45.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2020 08:45:19 -0700 (PDT) Message-Id: <5fdd8188b1d9b6efc2803b557b3ba344e184d22e.1598629517.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Derrick Stolee via GitGitGadget" Date: Fri, 28 Aug 2020 15:45:12 +0000 Subject: [PATCH v3 1/6] maintenance: optionally skip --auto process Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Derrick Stolee , Derrick Stolee , Derrick Stolee Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Derrick Stolee Some commands run 'git maintenance run --auto --[no-]quiet' after doing their normal work, as a way to keep repositories clean as they are used. Currently, users who do not want this maintenance to occur would set the 'gc.auto' config option to 0 to avoid the 'gc' task from running. However, this does not stop the extra process invocation. On Windows, this extra process invocation can be more expensive than necessary. Allow users to drop this extra process by setting 'maintenance.auto' to 'false'. Signed-off-by: Derrick Stolee --- Documentation/config/maintenance.txt | 5 +++++ run-command.c | 6 ++++++ t/t7900-maintenance.sh | 13 +++++++++++++ 3 files changed, 24 insertions(+) diff --git a/Documentation/config/maintenance.txt b/Documentation/config/maintenance.txt index a0706d8f09..06db758172 100644 --- a/Documentation/config/maintenance.txt +++ b/Documentation/config/maintenance.txt @@ -1,3 +1,8 @@ +maintenance.auto:: + This boolean config option controls whether some commands run + `git maintenance run --auto` after doing their normal work. Defaults + to true. + maintenance..enabled:: This boolean config option controls whether the maintenance task with name `` is run when no `--task` option is specified to diff --git a/run-command.c b/run-command.c index 2ee59acdc8..ea4d0fb4b1 100644 --- a/run-command.c +++ b/run-command.c @@ -7,6 +7,7 @@ #include "strbuf.h" #include "string-list.h" #include "quote.h" +#include "config.h" void child_process_init(struct child_process *child) { @@ -1868,8 +1869,13 @@ int run_processes_parallel_tr2(int n, get_next_task_fn get_next_task, int run_auto_maintenance(int quiet) { + int enabled; struct child_process maint = CHILD_PROCESS_INIT; + if (!git_config_get_bool("maintenance.auto", &enabled) && + !enabled) + return 0; + maint.git_cmd = 1; strvec_pushl(&maint.args, "maintenance", "run", "--auto", NULL); strvec_push(&maint.args, quiet ? "--quiet" : "--no-quiet"); diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh index 6f878b0141..e0ba19e1ff 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -26,6 +26,19 @@ test_expect_success 'run [--auto|--quiet]' ' test_subcommand git gc --no-quiet .enabled' ' git config maintenance.gc.enabled false && git config maintenance.commit-graph.enabled true && From patchwork Fri Aug 28 15:45:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derrick Stolee via GitGitGadget X-Patchwork-Id: 11743231 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5DDE81751 for ; Fri, 28 Aug 2020 15:45:42 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 3D82C2074A for ; Fri, 28 Aug 2020 15:45:42 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="S/mg2gLe" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728290AbgH1Ppl (ORCPT ); Fri, 28 Aug 2020 11:45:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39482 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1727993AbgH1PpW (ORCPT ); Fri, 28 Aug 2020 11:45:22 -0400 Received: from mail-wr1-x432.google.com (mail-wr1-x432.google.com [IPv6:2a00:1450:4864:20::432]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 196D7C06121B for ; Fri, 28 Aug 2020 08:45:22 -0700 (PDT) Received: by mail-wr1-x432.google.com with SMTP id b18so1725876wrs.7 for ; Fri, 28 Aug 2020 08:45:22 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=77+HngzKaQv1NyOkujyScNa2sa4WOlcHsO8S6LV+Guk=; b=S/mg2gLewf0MTy7Bx2UieVZ69upcgVbHtn0KgSrUAoS9u6atCiXBddK8liz0UlGSTK QKMym4gR7C/PZmz3iOpe6H9y8rFp+V5b6s/S00ZNuS84h9EAlC2dzwjs753p+566DsAl hOYFu6ifKWxOhqD+OWG6aqEfICJmTGFJwHx/QQaRdIF8tzJJMeHObOGP3YcHA3xbhWqu hfILGVKqn5jGsWRHIsPQDJFfC+l5+MT+8+mO3dW7mE9ovI9HKorWNHN9vabJphF5+PeJ 4WLsEpBd+oZHlxeDJXFz6JAaPJKDFnVmUfsRy5oYdISZcf4BkPR+xwo/RUHHDuafL3sb +JGw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=77+HngzKaQv1NyOkujyScNa2sa4WOlcHsO8S6LV+Guk=; b=O+AjrV5mu8zqSswI8V2As4xPpH5K0r2386KzQRqulnstXcIZMirZppxf1pcjXIRvhF CuBNXvqL2nA77XsrTVnMDI+LmDRLP6t4NuaHmbXl3v1+4y65JPnD4OQjYagTfWWOk9wK LmKf5ow3Iki25V4UPhxWi5LNuszYaWqSzw5/hIGJ3Djd82PLnZt3wJJNqeO7raMLDMLV OiJ6BzMN7gfSKisjQr19gmf89BE1zgi11g5khBWX+wcDo2uMN95agvcbLFY2Jct+qYIT qAssAB1969H/JZaT3E3lKjLyyuArbh/Bd3lGccXzsfN+amM1PajB5A/Yt2xQIO16ekhs PXzg== X-Gm-Message-State: AOAM530zbyMCfm+2JbSLIzQlFbCINymKuVFnyTf2uVChEleQRWOdTdyr 9QzARPzJGlqkvVehMuE0L8TIr2SoO7I= X-Google-Smtp-Source: ABdhPJz1OHzQZH5nyjwprv6vn25OiaPsEO4I5XTQNuH5EdLe7V8N7T+hj9w9lU2SnT+OOsRQ+VNFRQ== X-Received: by 2002:a5d:4444:: with SMTP id x4mr2068494wrr.110.1598629520316; Fri, 28 Aug 2020 08:45:20 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id o128sm2901906wmo.39.2020.08.28.08.45.19 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2020 08:45:19 -0700 (PDT) Message-Id: <41a067894d6fdcd966e4c376e9033d323af98ea7.1598629517.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Derrick Stolee via GitGitGadget" Date: Fri, 28 Aug 2020 15:45:13 +0000 Subject: [PATCH v3 2/6] maintenance: add --schedule option and config Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Derrick Stolee , Derrick Stolee , Derrick Stolee Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Derrick Stolee A user may want to run certain maintenance tasks based on frequency, not conditions given in the repository. For example, the user may want to perform a 'prefetch' task every hour, or 'gc' task every day. To assist, update the 'git maintenance run' command to include a '--schedule=' option. The allowed frequencies are 'hourly', 'daily', and 'weekly'. These values are also allowed in a new config value 'maintenance..schedule'. The 'git maintenance run --schedule=' checks the '*.schedule' config value for each enabled task to see if the configured frequency is at least as frequent as the frequency from the '--schedule' argument. We use the following order, for full clarity: 'hourly' > 'daily' > 'weekly' Use new 'enum schedule_priority' to track these values numerically. The following cron table would run the scheduled tasks with the correct frequencies: 0 1-23 * * * git -C maintenance run --scheduled=hourly 0 0 * * 1-6 git -C maintenance run --scheduled=daily 0 0 * * 0 git -C maintenance run --scheduled=weekly This cron schedule will run --scheduled=hourly every hour except at midnight. This avoids a concurrent run with the --scheduled=daily that runs at midnight every day except the first day of the week. This avoids a concurrent run with the --scheduled=weekly that runs at midnight on the first day of the week. Since --scheduled=daily also runs the 'hourly' tasks and --scheduled=weekly runs the 'hourly' and 'daily' tasks, we will still see all tasks run with the proper frequencies. Signed-off-by: Derrick Stolee --- Documentation/config/maintenance.txt | 5 +++ Documentation/git-maintenance.txt | 13 +++++- builtin/gc.c | 67 +++++++++++++++++++++++++--- t/t7900-maintenance.sh | 40 +++++++++++++++++ 4 files changed, 119 insertions(+), 6 deletions(-) diff --git a/Documentation/config/maintenance.txt b/Documentation/config/maintenance.txt index 06db758172..70585564fa 100644 --- a/Documentation/config/maintenance.txt +++ b/Documentation/config/maintenance.txt @@ -10,6 +10,11 @@ maintenance..enabled:: `--task` option exists. By default, only `maintenance.gc.enabled` is true. +maintenance..schedule:: + This config option controls whether or not the given `` runs + during a `git maintenance run --schedule=` command. The + value must be one of "hourly", "daily", or "weekly". + maintenance.commit-graph.auto:: This integer config option controls how often the `commit-graph` task should be run as part of `git maintenance run --auto`. If zero, then diff --git a/Documentation/git-maintenance.txt b/Documentation/git-maintenance.txt index b44efb05a3..3af5907b01 100644 --- a/Documentation/git-maintenance.txt +++ b/Documentation/git-maintenance.txt @@ -107,7 +107,18 @@ OPTIONS only if certain thresholds are met. For example, the `gc` task runs when the number of loose objects exceeds the number stored in the `gc.auto` config setting, or when the number of pack-files - exceeds the `gc.autoPackLimit` config setting. + exceeds the `gc.autoPackLimit` config setting. Not compatible with + the `--schedule` option. + +--schedule:: + When combined with the `run` subcommand, run maintenance tasks + only if certain time conditions are met, as specified by the + `maintenance..schedule` config value for each ``. + This config value specifies a number of seconds since the last + time that task ran, according to the `maintenance..lastRun` + config value. The tasks that are tested are those provided by + the `--task=` option(s) or those with + `maintenance..enabled` set to true. --quiet:: Do not report progress or other information over `stderr`. diff --git a/builtin/gc.c b/builtin/gc.c index f8459df04c..85a3370692 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -704,14 +704,51 @@ int cmd_gc(int argc, const char **argv, const char *prefix) return 0; } -static const char * const builtin_maintenance_run_usage[] = { - N_("git maintenance run [--auto] [--[no-]quiet] [--task=]"), +static const char *const builtin_maintenance_run_usage[] = { + N_("git maintenance run [--auto] [--[no-]quiet] [--task=] [--schedule]"), NULL }; +enum schedule_priority { + SCHEDULE_NONE = 0, + SCHEDULE_WEEKLY = 1, + SCHEDULE_DAILY = 2, + SCHEDULE_HOURLY = 3, +}; + +static enum schedule_priority parse_schedule(const char *value) +{ + if (!value) + return SCHEDULE_NONE; + if (!strcasecmp(value, "hourly")) + return SCHEDULE_HOURLY; + if (!strcasecmp(value, "daily")) + return SCHEDULE_DAILY; + if (!strcasecmp(value, "weekly")) + return SCHEDULE_WEEKLY; + return SCHEDULE_NONE; +} + +static int maintenance_opt_schedule(const struct option *opt, const char *arg, + int unset) +{ + enum schedule_priority *priority = opt->value; + + if (unset) + die(_("--no-schedule is not allowed")); + + *priority = parse_schedule(arg); + + if (!*priority) + die(_("unrecognized --schedule argument '%s'"), arg); + + return 0; +} + struct maintenance_run_opts { int auto_flag; int quiet; + enum schedule_priority schedule; }; /* Remember to update object flag allocation in object.h */ @@ -1159,6 +1196,8 @@ struct maintenance_task { maintenance_auto_fn *auto_condition; unsigned enabled:1; + enum schedule_priority schedule; + /* -1 if not selected. */ int selected_order; }; @@ -1250,8 +1289,10 @@ static int maintenance_run_tasks(struct maintenance_run_opts *opts) continue; if (opts->auto_flag && - (!tasks[i].auto_condition || - !tasks[i].auto_condition())) + (!tasks[i].auto_condition || !tasks[i].auto_condition())) + continue; + + if (opts->schedule && tasks[i].schedule < opts->schedule) continue; trace2_region_enter("maintenance", tasks[i].name, r); @@ -1274,13 +1315,23 @@ static void initialize_task_config(void) for (i = 0; i < TASK__COUNT; i++) { int config_value; + char *config_str; - strbuf_setlen(&config_name, 0); + strbuf_reset(&config_name); strbuf_addf(&config_name, "maintenance.%s.enabled", tasks[i].name); if (!git_config_get_bool(config_name.buf, &config_value)) tasks[i].enabled = config_value; + + strbuf_reset(&config_name); + strbuf_addf(&config_name, "maintenance.%s.schedule", + tasks[i].name); + + if (!git_config_get_string(config_name.buf, &config_str)) { + tasks[i].schedule = parse_schedule(config_str); + free(config_str); + } } strbuf_release(&config_name); @@ -1324,6 +1375,9 @@ static int maintenance_run(int argc, const char **argv, const char *prefix) struct option builtin_maintenance_run_options[] = { OPT_BOOL(0, "auto", &opts.auto_flag, N_("run tasks based on the state of the repository")), + OPT_CALLBACK(0, "schedule", &opts.schedule, N_("frequency"), + N_("run tasks based on frequency"), + maintenance_opt_schedule), OPT_BOOL(0, "quiet", &opts.quiet, N_("do not report progress or other information over stderr")), OPT_CALLBACK_F(0, "task", NULL, N_("task"), @@ -1344,6 +1398,9 @@ static int maintenance_run(int argc, const char **argv, const char *prefix) builtin_maintenance_run_usage, PARSE_OPT_STOP_AT_NON_OPTION); + if (opts.auto_flag && opts.schedule) + die(_("use at most one of --auto and --schedule=")); + if (argc != 0) usage_with_options(builtin_maintenance_run_usage, builtin_maintenance_run_options); diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh index e0ba19e1ff..328bbaa830 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -264,4 +264,44 @@ test_expect_success 'maintenance.incremental-repack.auto' ' done ' +test_expect_success '--auto and --schedule incompatible' ' + test_must_fail git maintenance run --auto --schedule=daily 2>err && + test_i18ngrep "at most one" err +' + +test_expect_success 'invalid --schedule value' ' + test_must_fail git maintenance run --schedule=annually 2>err && + test_i18ngrep "unrecognized --schedule" err +' + +test_expect_success '--schedule inheritance weekly -> daily -> hourly' ' + git config maintenance.loose-objects.enabled true && + git config maintenance.loose-objects.schedule hourly && + git config maintenance.commit-graph.enabled true && + git config maintenance.commit-graph.schedule daily && + git config maintenance.incremental-repack.enabled true && + git config maintenance.incremental-repack.schedule weekly && + + GIT_TRACE2_EVENT="$(pwd)/hourly.txt" \ + git maintenance run --schedule=hourly 2>/dev/null && + test_subcommand git prune-packed --quiet /dev/null && + test_subcommand git prune-packed --quiet /dev/null && + test_subcommand git prune-packed --quiet X-Patchwork-Id: 11743243 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 68EC513B6 for ; Fri, 28 Aug 2020 15:46:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 4340520872 for ; Fri, 28 Aug 2020 15:46:05 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="IHvb3Rmo" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728341AbgH1Ppy (ORCPT ); Fri, 28 Aug 2020 11:45:54 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39520 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728257AbgH1Ppf (ORCPT ); Fri, 28 Aug 2020 11:45:35 -0400 Received: from mail-wm1-x32a.google.com (mail-wm1-x32a.google.com [IPv6:2a00:1450:4864:20::32a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6D366C061235 for ; Fri, 28 Aug 2020 08:45:25 -0700 (PDT) Received: by mail-wm1-x32a.google.com with SMTP id x9so1329959wmi.2 for ; Fri, 28 Aug 2020 08:45:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=LJaF+KBq6DinuUhew6phz3UG9LLuWbKh+8DAyadGgBc=; b=IHvb3Rmo5iYzhYkCkD3TGKaqRdhdbhaNHyBoBSJoERwAzZpwRCz2zj5nzej+6dILEz Eiw0oGrez88m57PJIPM43Hm9ZUpiQfehcVc+8my3gVIA2ZuYOKWscY+PDF0FkD1nf6KE q6Lo+aZOpri6D2kEaHcG/JkJ1LqYhK5oDay2lLR2jDkkMzCn8qoCAI/8xjLC0emuNouR DEtIG3VMQdlWJyXeZuK7T8Qacj36ko4Bsbm74FW9jYQEj2xsLAeajJBz+bggZvep7gu6 ujK6JCbJKCLX4t8OnXAPC7R8DRSc55cD05260wm3ShmipS1SjKAaSfcw9UcaetHbfY7b nvdw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=LJaF+KBq6DinuUhew6phz3UG9LLuWbKh+8DAyadGgBc=; b=KeFaYj/7fAES5oIIOLamjgDtScRuRYdxYE3OwEVkVrnag7QLh6CHEhSm32GHtsIrKF C7scpvZCJTe1Lw9KLA6bKzzKUtNLu1u7rTnJBV/WriEp/xcsvV+zZn9ppw8+Gnwwv2yM 1JfEOflmBfvTfVHG1++o/50osRk6gaQEeALyDY6a4DVZM+QB/eEh9QJ/0sk+D4cf5c9u AIHvyQSQJtr6eHHyr3GTWtMzLBfYPmk39hAHeXs6GgeOF1LMAIqZMw+g8cr3EuGZijjR e/4sZhZkt1TJxLnO7SfeHoPqr7we/fntzdChcpCmhWN+gpHjOQL6l2rWniE+dtOkARi0 koaQ== X-Gm-Message-State: AOAM531QXuWfOJoZxdNV3AoVTuDitspacFrZy/3XEFzuATwFUVCL9TUV 5JmphhY4HlPmaj6V8EqP2ZzOpkPCpb4= X-Google-Smtp-Source: ABdhPJz47SJinppxZnX8Cw2V0uR02RlMegOI/V5XnXkooDQs5Nu+GotCtJgw1oap8kbUy6ln9LTMQw== X-Received: by 2002:a1c:bdc4:: with SMTP id n187mr2180535wmf.109.1598629521249; Fri, 28 Aug 2020 08:45:21 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id n21sm2740995wmc.11.2020.08.28.08.45.20 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2020 08:45:20 -0700 (PDT) Message-Id: In-Reply-To: References: From: "Derrick Stolee via GitGitGadget" Date: Fri, 28 Aug 2020 15:45:14 +0000 Subject: [PATCH v3 3/6] for-each-repo: run subcommands on configured repos Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Derrick Stolee , Derrick Stolee , Derrick Stolee Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Derrick Stolee It can be helpful to store a list of repositories in global or system config and then iterate Git commands on that list. Create a new builtin that makes this process simple for experts. We will use this builtin to run scheduled maintenance on all configured repositories in a future change. The test is very simple, but does highlight that the "--" argument is optional. Signed-off-by: Derrick Stolee --- .gitignore | 1 + Documentation/git-for-each-repo.txt | 59 +++++++++++++++++++++++++++++ Makefile | 1 + builtin.h | 1 + builtin/for-each-repo.c | 58 ++++++++++++++++++++++++++++ command-list.txt | 1 + git.c | 1 + t/t0068-for-each-repo.sh | 30 +++++++++++++++ 8 files changed, 152 insertions(+) create mode 100644 Documentation/git-for-each-repo.txt create mode 100644 builtin/for-each-repo.c create mode 100755 t/t0068-for-each-repo.sh diff --git a/.gitignore b/.gitignore index a5808fa30d..5eb2a2be71 100644 --- a/.gitignore +++ b/.gitignore @@ -67,6 +67,7 @@ /git-filter-branch /git-fmt-merge-msg /git-for-each-ref +/git-for-each-repo /git-format-patch /git-fsck /git-fsck-objects diff --git a/Documentation/git-for-each-repo.txt b/Documentation/git-for-each-repo.txt new file mode 100644 index 0000000000..94bd19da26 --- /dev/null +++ b/Documentation/git-for-each-repo.txt @@ -0,0 +1,59 @@ +git-for-each-repo(1) +==================== + +NAME +---- +git-for-each-repo - Run a Git command on a list of repositories + + +SYNOPSIS +-------- +[verse] +'git for-each-repo' --config= [--] + + +DESCRIPTION +----------- +Run a Git command on a list of repositories. The arguments after the +known options or `--` indicator are used as the arguments for the Git +subprocess. + +THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE. + +For example, we could run maintenance on each of a list of repositories +stored in a `maintenance.repo` config variable using + +------------- +git for-each-repo --config=maintenance.repo maintenance run +------------- + +This will run `git -C maintenance run` for each value `` +in the multi-valued config variable `maintenance.repo`. + + +OPTIONS +------- +--config=:: + Use the given config variable as a multi-valued list storing + absolute path names. Iterate on that list of paths to run + the given arguments. ++ +These config values are loaded from system, global, and local Git config, +as available. If `git for-each-repo` is run in a directory that is not a +Git repository, then only the system and global config is used. + + +SUBPROCESS BEHAVIOR +------------------- + +If any `git -C ` subprocess returns a non-zero exit code, +then the `git for-each-repo` process returns that exit code without running +more subprocesses. + +Each `git -C ` subprocess inherits the standard file +descriptors `stdin`, `stdout`, and `stderr`. + + +GIT +--- +Part of the linkgit:git[1] suite diff --git a/Makefile b/Makefile index 65f8cfb236..7c588ff036 100644 --- a/Makefile +++ b/Makefile @@ -1071,6 +1071,7 @@ BUILTIN_OBJS += builtin/fetch-pack.o BUILTIN_OBJS += builtin/fetch.o BUILTIN_OBJS += builtin/fmt-merge-msg.o BUILTIN_OBJS += builtin/for-each-ref.o +BUILTIN_OBJS += builtin/for-each-repo.o BUILTIN_OBJS += builtin/fsck.o BUILTIN_OBJS += builtin/gc.o BUILTIN_OBJS += builtin/get-tar-commit-id.o diff --git a/builtin.h b/builtin.h index 17c1c0ce49..ff7c6e5aa9 100644 --- a/builtin.h +++ b/builtin.h @@ -150,6 +150,7 @@ int cmd_fetch(int argc, const char **argv, const char *prefix); int cmd_fetch_pack(int argc, const char **argv, const char *prefix); int cmd_fmt_merge_msg(int argc, const char **argv, const char *prefix); int cmd_for_each_ref(int argc, const char **argv, const char *prefix); +int cmd_for_each_repo(int argc, const char **argv, const char *prefix); int cmd_format_patch(int argc, const char **argv, const char *prefix); int cmd_fsck(int argc, const char **argv, const char *prefix); int cmd_gc(int argc, const char **argv, const char *prefix); diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c new file mode 100644 index 0000000000..5bba623ff1 --- /dev/null +++ b/builtin/for-each-repo.c @@ -0,0 +1,58 @@ +#include "cache.h" +#include "config.h" +#include "builtin.h" +#include "parse-options.h" +#include "run-command.h" +#include "string-list.h" + +static const char * const for_each_repo_usage[] = { + N_("git for-each-repo --config= "), + NULL +}; + +static int run_command_on_repo(const char *path, + void *cbdata) +{ + int i; + struct child_process child = CHILD_PROCESS_INIT; + struct strvec *args = (struct strvec *)cbdata; + + child.git_cmd = 1; + strvec_pushl(&child.args, "-C", path, NULL); + + for (i = 0; i < args->nr; i++) + strvec_push(&child.args, args->v[i]); + + return run_command(&child); +} + +int cmd_for_each_repo(int argc, const char **argv, const char *prefix) +{ + static const char *config_key = NULL; + int i, result = 0; + const struct string_list *values; + struct strvec args = STRVEC_INIT; + + const struct option options[] = { + OPT_STRING(0, "config", &config_key, N_("config"), + N_("config key storing a list of repository paths")), + OPT_END() + }; + + argc = parse_options(argc, argv, prefix, options, for_each_repo_usage, + PARSE_OPT_STOP_AT_NON_OPTION); + + if (!config_key) + die(_("missing --config=")); + + for (i = 0; i < argc; i++) + strvec_push(&args, argv[i]); + + values = repo_config_get_value_multi(the_repository, + config_key); + + for (i = 0; !result && i < values->nr; i++) + result = run_command_on_repo(values->items[i].string, &args); + + return result; +} diff --git a/command-list.txt b/command-list.txt index 0e3204e7d1..581499be82 100644 --- a/command-list.txt +++ b/command-list.txt @@ -94,6 +94,7 @@ git-fetch-pack synchingrepositories git-filter-branch ancillarymanipulators git-fmt-merge-msg purehelpers git-for-each-ref plumbinginterrogators +git-for-each-repo plumbinginterrogators git-format-patch mainporcelain git-fsck ancillaryinterrogators complete git-gc mainporcelain diff --git a/git.c b/git.c index 24f250d29a..1cab64b5d1 100644 --- a/git.c +++ b/git.c @@ -511,6 +511,7 @@ static struct cmd_struct commands[] = { { "fetch-pack", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT }, { "fmt-merge-msg", cmd_fmt_merge_msg, RUN_SETUP }, { "for-each-ref", cmd_for_each_ref, RUN_SETUP }, + { "for-each-repo", cmd_for_each_repo, RUN_SETUP_GENTLY }, { "format-patch", cmd_format_patch, RUN_SETUP }, { "fsck", cmd_fsck, RUN_SETUP }, { "fsck-objects", cmd_fsck, RUN_SETUP }, diff --git a/t/t0068-for-each-repo.sh b/t/t0068-for-each-repo.sh new file mode 100755 index 0000000000..136b4ec839 --- /dev/null +++ b/t/t0068-for-each-repo.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +test_description='git for-each-repo builtin' + +. ./test-lib.sh + +test_expect_success 'run based on configured value' ' + git init one && + git init two && + git init three && + git -C two commit --allow-empty -m "DID NOT RUN" && + git config run.key "$TRASH_DIRECTORY/one" && + git config --add run.key "$TRASH_DIRECTORY/three" && + git for-each-repo --config=run.key commit --allow-empty -m "ran" && + git -C one log -1 --pretty=format:%s >message && + grep ran message && + git -C two log -1 --pretty=format:%s >message && + ! grep ran message && + git -C three log -1 --pretty=format:%s >message && + grep ran message && + git for-each-repo --config=run.key -- commit --allow-empty -m "ran again" && + git -C one log -1 --pretty=format:%s >message && + grep again message && + git -C two log -1 --pretty=format:%s >message && + ! grep again message && + git -C three log -1 --pretty=format:%s >message && + grep again message +' + +test_done From patchwork Fri Aug 28 15:45:15 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derrick Stolee via GitGitGadget X-Patchwork-Id: 11743233 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 64E5C13A4 for ; Fri, 28 Aug 2020 15:45:44 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 437F92071B for ; Fri, 28 Aug 2020 15:45:44 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="AJ3DUESr" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728298AbgH1Ppm (ORCPT ); Fri, 28 Aug 2020 11:45:42 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39488 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728222AbgH1PpY (ORCPT ); Fri, 28 Aug 2020 11:45:24 -0400 Received: from mail-wr1-x444.google.com (mail-wr1-x444.google.com [IPv6:2a00:1450:4864:20::444]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CEE60C061232 for ; Fri, 28 Aug 2020 08:45:23 -0700 (PDT) Received: by mail-wr1-x444.google.com with SMTP id e16so1725375wrm.2 for ; Fri, 28 Aug 2020 08:45:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=SfvL3JOcL/ldtyaSQB9lmmRpnkTZTst+HjJza8s3AfA=; b=AJ3DUESrQD69MVTREsu3NlqBazzFXc5rVgeKCx7hY/aq/j41WOkS2YVflJfws9nysa 9qEEEb4xw6Ur8SCE4noa6CmS5ghtaPpIdAy/E2slcgHrxKkC3R/f1wS+l8IqjENL60Uh Z67g9x6OsgO4I2FZh685JDLdOEw5IGhPZzxNbG0b9KVZXIBqkV7wVGwpWF0Xnu69t6Im f9tjPQXkKSZ9vbthvtPtl8Jfyusv+zu9kTkxDMenfYxp14GfcExd60uDfB8pFD+91pzv AgkZtRpnfNhURgLGzxADeKMGk5jQxra3yKcnIEC29omcEMRo5T6uCMI++OFMY1uVDpSe s8eA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=SfvL3JOcL/ldtyaSQB9lmmRpnkTZTst+HjJza8s3AfA=; b=gg3En8v1c4OZgPygAtKaHVkQd7p7xmT9odxYjufZgufK3g3PM0Ab09hsAwnBs5CeS2 pUBwSAwcqd9vJXEHA0vx+7hhcwq82Zu3WgZFocEH8gkSsdRAWLEVgwD/NrSw/u0jKV/O NhYacG3/gsD+4w3vszBSlpPr4ZzFS2++8YoPaYT3mkGsr8K5RZBh8lGloTs4cE571Fqw QhxIUfqMmpcxf7nfdoeFED8fLKqji/BiP6YYIC7ety5nk2M68F+EA7+5A5RHTK70bmHR nEE4u0pUCB/UErKI6pLX63cVXedGk7RLPe8iNraxDM5LWNz/Jb/f4jNcJSzvD+p81Itw 8QsQ== X-Gm-Message-State: AOAM533IjmLBNjjBnZjXWhWNMs0/Gzzuolw2Zqt3Ao0TurCYGdYoRbx8 fT1Fa8su6B7+BXmwwjb0ICAqZ68LyJ0= X-Google-Smtp-Source: ABdhPJxe5pNMg4npK1jrG6d90lQ6e2pdxI3aDothDtcL51HOPieKAnlfYFIrMAS6M6Lvc8ZadpJ77A== X-Received: by 2002:adf:ed88:: with SMTP id c8mr1960183wro.233.1598629522203; Fri, 28 Aug 2020 08:45:22 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id t14sm3198885wrg.38.2020.08.28.08.45.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2020 08:45:21 -0700 (PDT) Message-Id: In-Reply-To: References: From: "Derrick Stolee via GitGitGadget" Date: Fri, 28 Aug 2020 15:45:15 +0000 Subject: [PATCH v3 4/6] maintenance: add [un]register subcommands Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Derrick Stolee , Derrick Stolee , Derrick Stolee Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Derrick Stolee In preparation for launching background maintenance from the 'git maintenance' builtin, create register/unregister subcommands. These commands update the new 'maintenance.repos' config option in the global config so the background maintenance job knows which repositories to maintain. These commands allow users to add a repository to the background maintenance list without disrupting the actual maintenance mechanism. For example, a user can run 'git maintenance register' when no background maintenance is running and it will not start the background maintenance. A later update to start running background maintenance will then pick up this repository automatically. The opposite example is that a user can run 'git maintenance unregister' to remove the current repository from background maintenance without halting maintenance for other repositories. Signed-off-by: Derrick Stolee --- Documentation/git-maintenance.txt | 14 ++++++++ builtin/gc.c | 55 ++++++++++++++++++++++++++++++- t/t7900-maintenance.sh | 17 +++++++++- 3 files changed, 84 insertions(+), 2 deletions(-) diff --git a/Documentation/git-maintenance.txt b/Documentation/git-maintenance.txt index 3af5907b01..78d0d8df91 100644 --- a/Documentation/git-maintenance.txt +++ b/Documentation/git-maintenance.txt @@ -29,6 +29,15 @@ Git repository. SUBCOMMANDS ----------- +register:: + Initialize Git config values so any scheduled maintenance will + start running on this repository. This adds the repository to the + `maintenance.repo` config variable in the current user's global + config and enables some recommended configuration values for + `maintenance..schedule`. The tasks that are enabled are safe + for running in the background without disrupting foreground + processes. + run:: Run one or more maintenance tasks. If one or more `--task` options are specified, then those tasks are run in that order. Otherwise, @@ -36,6 +45,11 @@ run:: config options are true. By default, only `maintenance.gc.enabled` is true. +unregister:: + Remove the current repository from background maintenance. This + only removes the repository from the configured list. It does not + stop the background maintenance processes from running. + TASKS ----- diff --git a/builtin/gc.c b/builtin/gc.c index 85a3370692..ec77e8d2fa 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -1407,7 +1407,56 @@ static int maintenance_run(int argc, const char **argv, const char *prefix) return maintenance_run_tasks(&opts); } -static const char builtin_maintenance_usage[] = N_("git maintenance run []"); +static int maintenance_register(void) +{ + struct child_process config_set = CHILD_PROCESS_INIT; + struct child_process config_get = CHILD_PROCESS_INIT; + + /* There is no current repository, so skip registering it */ + if (!the_repository || !the_repository->gitdir) + return 0; + + config_get.git_cmd = 1; + strvec_pushl(&config_get.args, "config", "--global", "--get", "maintenance.repo", + the_repository->worktree ? the_repository->worktree + : the_repository->gitdir, + NULL); + config_get.out = -1; + + if (start_command(&config_get)) + return error(_("failed to run 'git config'")); + + /* We already have this value in our config! */ + if (!finish_command(&config_get)) + return 0; + + config_set.git_cmd = 1; + strvec_pushl(&config_set.args, "config", "--add", "--global", "maintenance.repo", + the_repository->worktree ? the_repository->worktree + : the_repository->gitdir, + NULL); + + return run_command(&config_set); +} + +static int maintenance_unregister(void) +{ + struct child_process config_unset = CHILD_PROCESS_INIT; + + if (!the_repository || !the_repository->gitdir) + return error(_("no current repository to unregister")); + + config_unset.git_cmd = 1; + strvec_pushl(&config_unset.args, "config", "--global", "--unset", + "maintenance.repo", + the_repository->worktree ? the_repository->worktree + : the_repository->gitdir, + NULL); + + return run_command(&config_unset); +} + +static const char builtin_maintenance_usage[] = N_("git maintenance []"); int cmd_maintenance(int argc, const char **argv, const char *prefix) { @@ -1416,6 +1465,10 @@ int cmd_maintenance(int argc, const char **argv, const char *prefix) if (!strcmp(argv[1], "run")) return maintenance_run(argc - 1, argv + 1, prefix); + if (!strcmp(argv[1], "register")) + return maintenance_register(); + if (!strcmp(argv[1], "unregister")) + return maintenance_unregister(); die(_("invalid subcommand: %s"), argv[1]); } diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh index 328bbaa830..272d1605d2 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -9,7 +9,7 @@ GIT_TEST_MULTI_PACK_INDEX=0 test_expect_success 'help text' ' test_expect_code 129 git maintenance -h 2>err && - test_i18ngrep "usage: git maintenance run" err && + test_i18ngrep "usage: git maintenance " err && test_expect_code 128 git maintenance barf 2>err && test_i18ngrep "invalid subcommand: barf" err ' @@ -304,4 +304,19 @@ test_expect_success '--schedule inheritance weekly -> daily -> hourly' ' test_subcommand git multi-pack-index write --no-progress before && + git maintenance register && + git config --global --get-all maintenance.repo >actual && + cp before after && + pwd >>after && + test_cmp after actual && + git maintenance unregister && + git config --global --get-all maintenance.repo >actual && + test_cmp before actual +' + test_done From patchwork Fri Aug 28 15:45:16 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derrick Stolee via GitGitGadget X-Patchwork-Id: 11743239 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 3661D13B6 for ; Fri, 28 Aug 2020 15:45:49 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 17D0A2074A for ; Fri, 28 Aug 2020 15:45:49 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="WjnJ3fRC" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728305AbgH1Ppr (ORCPT ); Fri, 28 Aug 2020 11:45:47 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39492 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728235AbgH1PpZ (ORCPT ); Fri, 28 Aug 2020 11:45:25 -0400 Received: from mail-wm1-x343.google.com (mail-wm1-x343.google.com [IPv6:2a00:1450:4864:20::343]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F2FC8C061234 for ; Fri, 28 Aug 2020 08:45:24 -0700 (PDT) Received: by mail-wm1-x343.google.com with SMTP id y8so1076081wma.0 for ; Fri, 28 Aug 2020 08:45:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=PDiFpRI1L5D5O35ym9PuX4yaU0hZeV7/cS9qocmQuek=; b=WjnJ3fRC/MO1tZ5tSJ94hYw74VFtvPr3yIvW19La36QM/JyJX9M/5ORnCO60+Mbwh2 aVDGQSBPdBoQ79lD2USRRgK5VnS4C4hgOD/IHGBkvYwD1tFCUx6eVaI0nPVHUR9hsXqs 89gSH2gMA2JiPzyy+n23/wGq0N8krHXBURmWliUOkg0L/6bt8BSjN8cWtc+rfDOWHM9t P38EjMJIsFB2B9rDUndlTuxtmAfY70iDaE772IS3KHRjlsozgQiu84OHfvCWBZNPcOqa o0iBXtxwiHIhuG6WRk4uMYd+Uwdi1T27HOT798N0SBZE41gY70CjwlAkjc9Su83D/5Qw txFA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=PDiFpRI1L5D5O35ym9PuX4yaU0hZeV7/cS9qocmQuek=; b=BIpIm1kO1BZ9CKMrl1kTlLHx4eRiXaenAo0qwI7wuOtGasUm4GrDJzNaY6yNRg5JCz hvH8WomHdE1OER/c+Fohq5RnDRpLK9aiL3X53ubl3xfuVzAiUKyAuAW+IRBbfUY60xvU PNXoclfBIjcFwnCme4Xp5uZmJMtUkW277h+5gs1PZJRdSe8v/nlfnyVLBt4jiqkS/LU/ E5+FEKdpqsN2GIcLFlqrPjS26pvRMXWj6GNupO2VHOSB+Hs40DPfUHIzl0FXalmmrYQl juwTwiDrt+kocGgJ5oZyJTDt9sOkkaVCQ6BO+jQEAQUxszQITwFadr6F7S+Eh2Q+kmPG 7iqg== X-Gm-Message-State: AOAM533XysG1dzLc+5SuWDtxQnNE37o3bWwDO7Td+AnA7VWRgx3WQyI7 hrSUmIsytZbbf3wLzGmvKjoo27ncl20= X-Google-Smtp-Source: ABdhPJxjsjWFvYjxGJMWYRLQS/m52veGJhHYtXC9m3l+0gzTYsNxSxgp9u7vWs214/VYVk9wWPseIw== X-Received: by 2002:a1c:2501:: with SMTP id l1mr2460375wml.16.1598629523070; Fri, 28 Aug 2020 08:45:23 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id y3sm2659091wrs.36.2020.08.28.08.45.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2020 08:45:22 -0700 (PDT) Message-Id: In-Reply-To: References: From: "Derrick Stolee via GitGitGadget" Date: Fri, 28 Aug 2020 15:45:16 +0000 Subject: [PATCH v3 5/6] maintenance: add start/stop subcommands Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Derrick Stolee , Derrick Stolee , Derrick Stolee Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Derrick Stolee Add new subcommands to 'git maintenance' that start or stop background maintenance using 'cron', when available. This integration is as simple as I could make it, barring some implementation complications. The schedule is laid out as follows: 0 1-23 * * * $cmd maintenance run --schedule=hourly 0 0 * * 1-6 $cmd maintenance run --schedule=daily 0 0 * * 0 $cmd maintenance run --schedule=weekly where $cmd is a properly-qualified 'git for-each-repo' execution: $cmd=$path/git --exec-path=$path for-each-repo --config=maintenance.repo where $path points to the location of the Git executable running 'git maintenance start'. This is critical for systems with multiple versions of Git. Specifically, macOS has a system version at '/usr/bin/git' while the version that users can install resides at '/usr/local/bin/git' (symlinked to '/usr/local/libexec/git-core/git'). This will also use your locally-built version if you build and run this in your development environment without installing first. This conditional schedule avoids having cron launch multiple 'git for-each-repo' commands in parallel. Such parallel commands would likely lead to the 'hourly' and 'daily' tasks competing over the object database lock. This could lead to to some tasks never being run! Since the --schedule= argument will run all tasks with _at least_ the given frequency, the daily runs will also run the hourly tasks. Similarly, the weekly runs will also run the daily and hourly tasks. The GIT_TEST_CRONTAB environment variable is not intended for users to edit, but instead as a way to mock the 'crontab [-l]' command. This variable is set in test-lib.sh to avoid a future test from accidentally running anything with the cron integration from modifying the user's schedule. We use GIT_TEST_CRONTAB='test-tool crontab ' in our tests to check how the schedule is modified in 'git maintenance (start|stop)' commands. Signed-off-by: Derrick Stolee --- Documentation/git-maintenance.txt | 11 +++ Makefile | 1 + builtin/gc.c | 124 ++++++++++++++++++++++++++++++ t/helper/test-crontab.c | 35 +++++++++ t/helper/test-tool.c | 1 + t/helper/test-tool.h | 1 + t/t7900-maintenance.sh | 28 +++++++ t/test-lib.sh | 6 ++ 8 files changed, 207 insertions(+) create mode 100644 t/helper/test-crontab.c diff --git a/Documentation/git-maintenance.txt b/Documentation/git-maintenance.txt index 78d0d8df91..7f8c279fe8 100644 --- a/Documentation/git-maintenance.txt +++ b/Documentation/git-maintenance.txt @@ -45,6 +45,17 @@ run:: config options are true. By default, only `maintenance.gc.enabled` is true. +start:: + Start running maintenance on the current repository. This performs + the same config updates as the `register` subcommand, then updates + the background scheduler to run `git maintenance run --scheduled` + on an hourly basis. + +stop:: + Halt the background maintenance schedule. The current repository + is not removed from the list of maintained repositories, in case + the background maintenance is restarted later. + unregister:: Remove the current repository from background maintenance. This only removes the repository from the configured list. It does not diff --git a/Makefile b/Makefile index 7c588ff036..c39b39bd7d 100644 --- a/Makefile +++ b/Makefile @@ -690,6 +690,7 @@ TEST_BUILTINS_OBJS += test-advise.o TEST_BUILTINS_OBJS += test-bloom.o TEST_BUILTINS_OBJS += test-chmtime.o TEST_BUILTINS_OBJS += test-config.o +TEST_BUILTINS_OBJS += test-crontab.o TEST_BUILTINS_OBJS += test-ctype.o TEST_BUILTINS_OBJS += test-date.o TEST_BUILTINS_OBJS += test-delta.o diff --git a/builtin/gc.c b/builtin/gc.c index ec77e8d2fa..9914417e25 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -32,6 +32,7 @@ #include "remote.h" #include "midx.h" #include "object-store.h" +#include "exec-cmd.h" #define FAILED_RUN "failed to run %s" @@ -1456,6 +1457,125 @@ static int maintenance_unregister(void) return run_command(&config_unset); } +#define BEGIN_LINE "# BEGIN GIT MAINTENANCE SCHEDULE" +#define END_LINE "# END GIT MAINTENANCE SCHEDULE" + +static int update_background_schedule(int run_maintenance) +{ + int result = 0; + int in_old_region = 0; + struct child_process crontab_list = CHILD_PROCESS_INIT; + struct child_process crontab_edit = CHILD_PROCESS_INIT; + FILE *cron_list, *cron_in; + const char *crontab_name; + struct strbuf line = STRBUF_INIT; + struct lock_file lk; + char *lock_path = xstrfmt("%s/schedule", the_repository->objects->odb->path); + + if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0) + return error(_("another process is scheduling background maintenance")); + + crontab_name = getenv("GIT_TEST_CRONTAB"); + if (!crontab_name) + crontab_name = "crontab"; + + strvec_split(&crontab_list.args, crontab_name); + strvec_push(&crontab_list.args, "-l"); + crontab_list.in = -1; + crontab_list.out = dup(lk.tempfile->fd); + crontab_list.git_cmd = 0; + + if (start_command(&crontab_list)) { + result = error(_("failed to run 'crontab -l'; your system might not support 'cron'")); + goto cleanup; + } + + /* Ignore exit code, as an empty crontab will return error. */ + finish_command(&crontab_list); + + /* + * Read from the .lock file, filtering out the old + * schedule while appending the new schedule. + */ + cron_list = fdopen(lk.tempfile->fd, "r"); + rewind(cron_list); + + strvec_split(&crontab_edit.args, crontab_name); + crontab_edit.in = -1; + crontab_edit.git_cmd = 0; + + if (start_command(&crontab_edit)) { + result = error(_("failed to run 'crontab'; your system might not support 'cron'")); + goto cleanup; + } + + cron_in = fdopen(crontab_edit.in, "w"); + if (!cron_in) { + result = error(_("failed to open stdin of 'crontab'")); + goto done_editing; + } + + while (!strbuf_getline_lf(&line, cron_list)) { + if (!in_old_region && !strcmp(line.buf, BEGIN_LINE)) + in_old_region = 1; + if (in_old_region) + continue; + fprintf(cron_in, "%s\n", line.buf); + if (in_old_region && !strcmp(line.buf, END_LINE)) + in_old_region = 0; + } + + if (run_maintenance) { + struct strbuf line_format = STRBUF_INIT; + const char *exec_path = git_exec_path(); + + fprintf(cron_in, "%s\n", BEGIN_LINE); + fprintf(cron_in, + "# The following schedule was created by Git\n"); + fprintf(cron_in, "# Any edits made in this region might be\n"); + fprintf(cron_in, + "# replaced in the future by a Git command.\n\n"); + + strbuf_addf(&line_format, + "%%s %%s * * %%s \"%s/git\" --exec-path=\"%s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%%s\n", + exec_path, exec_path); + fprintf(cron_in, line_format.buf, "0", "1-23", "*", "hourly"); + fprintf(cron_in, line_format.buf, "0", "0", "1-6", "daily"); + fprintf(cron_in, line_format.buf, "0", "0", "0", "weekly"); + strbuf_release(&line_format); + + fprintf(cron_in, "\n%s\n", END_LINE); + } + + fflush(cron_in); + fclose(cron_in); + close(crontab_edit.in); + +done_editing: + if (finish_command(&crontab_edit)) { + result = error(_("'crontab' died")); + goto cleanup; + } + fclose(cron_list); + +cleanup: + rollback_lock_file(&lk); + return result; +} + +static int maintenance_start(void) +{ + if (maintenance_register()) + warning(_("failed to add repo to global config")); + + return update_background_schedule(1); +} + +static int maintenance_stop(void) +{ + return update_background_schedule(0); +} + static const char builtin_maintenance_usage[] = N_("git maintenance []"); int cmd_maintenance(int argc, const char **argv, const char *prefix) @@ -1465,6 +1585,10 @@ int cmd_maintenance(int argc, const char **argv, const char *prefix) if (!strcmp(argv[1], "run")) return maintenance_run(argc - 1, argv + 1, prefix); + if (!strcmp(argv[1], "start")) + return maintenance_start(); + if (!strcmp(argv[1], "stop")) + return maintenance_stop(); if (!strcmp(argv[1], "register")) return maintenance_register(); if (!strcmp(argv[1], "unregister")) diff --git a/t/helper/test-crontab.c b/t/helper/test-crontab.c new file mode 100644 index 0000000000..f5db6319c6 --- /dev/null +++ b/t/helper/test-crontab.c @@ -0,0 +1,35 @@ +#include "test-tool.h" +#include "cache.h" + +/* + * Usage: test-tool cron [-l] + * + * If -l is specified, then write the contents of to stdou. + * Otherwise, write from stdin into . + */ +int cmd__crontab(int argc, const char **argv) +{ + char a; + FILE *from, *to; + + if (argc == 3 && !strcmp(argv[2], "-l")) { + from = fopen(argv[1], "r"); + if (!from) + return 0; + to = stdout; + } else if (argc == 2) { + from = stdin; + to = fopen(argv[1], "w"); + } else + return error("unknown arguments"); + + while ((a = fgetc(from)) != EOF) + fputc(a, to); + + if (argc == 3) + fclose(from); + else + fclose(to); + + return 0; +} diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index 590b2efca7..432b49d948 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -18,6 +18,7 @@ static struct test_cmd cmds[] = { { "bloom", cmd__bloom }, { "chmtime", cmd__chmtime }, { "config", cmd__config }, + { "crontab", cmd__crontab }, { "ctype", cmd__ctype }, { "date", cmd__date }, { "delta", cmd__delta }, diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index ddc8e990e9..7c3281e071 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -8,6 +8,7 @@ int cmd__advise_if_enabled(int argc, const char **argv); int cmd__bloom(int argc, const char **argv); int cmd__chmtime(int argc, const char **argv); int cmd__config(int argc, const char **argv); +int cmd__crontab(int argc, const char **argv); int cmd__ctype(int argc, const char **argv); int cmd__date(int argc, const char **argv); int cmd__delta(int argc, const char **argv); diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh index 272d1605d2..8803fcf621 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -319,4 +319,32 @@ test_expect_success 'register and unregister' ' test_cmp before actual ' +test_expect_success 'start from empty cron table' ' + GIT_TEST_CRONTAB="test-tool crontab cron.txt" git maintenance start && + + # start registers the repo + git config --get --global maintenance.repo "$(pwd)" && + + grep "for-each-repo --config=maintenance.repo maintenance run --schedule=daily" cron.txt && + grep "for-each-repo --config=maintenance.repo maintenance run --schedule=hourly" cron.txt && + grep "for-each-repo --config=maintenance.repo maintenance run --schedule=weekly" cron.txt +' + +test_expect_success 'stop from existing schedule' ' + GIT_TEST_CRONTAB="test-tool crontab cron.txt" git maintenance stop && + + # stop does not unregister the repo + git config --get --global maintenance.repo "$(pwd)" && + + # Operation is idempotent + GIT_TEST_CRONTAB="test-tool crontab cron.txt" git maintenance stop && + test_must_be_empty cron.txt +' + +test_expect_success 'start preserves existing schedule' ' + echo "Important information!" >cron.txt && + GIT_TEST_CRONTAB="test-tool crontab cron.txt" git maintenance start && + grep "Important information!" cron.txt +' + test_done diff --git a/t/test-lib.sh b/t/test-lib.sh index ef31f40037..4a60d1ed76 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1702,3 +1702,9 @@ test_lazy_prereq SHA1 ' test_lazy_prereq REBASE_P ' test -z "$GIT_TEST_SKIP_REBASE_P" ' + +# Ensure that no test accidentally triggers a Git command +# that runs 'crontab', affecting a user's cron schedule. +# Tests that verify the cron integration must set this locally +# to avoid errors. +GIT_TEST_CRONTAB="exit 1" From patchwork Fri Aug 28 15:45:17 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Derrick Stolee via GitGitGadget X-Patchwork-Id: 11743241 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 8B33313A4 for ; Fri, 28 Aug 2020 15:45:54 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6CE902071B for ; Fri, 28 Aug 2020 15:45:54 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="G6iyo8tk" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1728335AbgH1Ppu (ORCPT ); Fri, 28 Aug 2020 11:45:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39522 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1728267AbgH1Ppf (ORCPT ); Fri, 28 Aug 2020 11:45:35 -0400 Received: from mail-wm1-x341.google.com (mail-wm1-x341.google.com [IPv6:2a00:1450:4864:20::341]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B744FC061236 for ; Fri, 28 Aug 2020 08:45:25 -0700 (PDT) Received: by mail-wm1-x341.google.com with SMTP id c19so1072679wmd.1 for ; Fri, 28 Aug 2020 08:45:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=message-id:in-reply-to:references:from:date:subject:fcc :content-transfer-encoding:mime-version:to:cc; bh=t13EbWJeubyTEm19LcAgWKvrkpEFAPWkjSKqbw4gHQE=; b=G6iyo8tkrJcuE4ISzalx3ojtsg8tkWlUPpfA0qV7oHaMhO+3YOrcpCWXdE+RftE6Mg +KISiHvZSc48S8dW+hmYSyx47i/MnrsWlEo9kNqfbgZAgMAY9Ml0mqfaHjdS+WxwpoG2 bFtmOm70UdJjro5uxByYXRUcaZWCE2O8rsq5g7EtWj28N7GYnk4DFRn4ZEsx2jqe6FoH 64VBxPMWu+hLQZN8Eo11uXN69FSWYcOgs04hs1KAsfmJm0YfrJ96RnKij2Ni75qVEafm FSPa8Y0g0vT0sHSLVMiEcuWvSjKVVfDL/JFyG6RuESDfgYTQvUAQBYRH3BX3XRP/5OY2 scEQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:message-id:in-reply-to:references:from:date :subject:fcc:content-transfer-encoding:mime-version:to:cc; bh=t13EbWJeubyTEm19LcAgWKvrkpEFAPWkjSKqbw4gHQE=; b=WI7ESevmczorSQBhPHE49q1OcfaeKxt5x18ioKUIxbiwqhbUZmdSDK0GtGcuxAq/GN Ci2hL4/ed11bIEOT9Q+8X3NdUU8A54QxGLwIQk+mJxlLWHUGDOR0gsT08BiE/PXeQYsU fNH6Vz4TXbNgeHwWPkqTiPpumd1hoffuemLRd255TrMMvEdq0XKiqvyAukKpYaCqpbjF mnPytoSGBw0Ikk7zvUmMYceluWB1eyO6JdHNEuoEObEvP66HJaCzs44Tp2MZalh3xqYJ fW+1W/ylFi2hGaoVPm7DyLawfSju9mUHM8S0UTeol4mZzhH/lXB/tXtXSGpwvhVW4pAv iXPw== X-Gm-Message-State: AOAM532tkF/Z2ELY6Bc3UVMLjnNaDLxnHF3Lmlnw9hToh275Vryq/NgH siwz0o1Y2IsWqzp2k49hXQ/P/HjUVCU= X-Google-Smtp-Source: ABdhPJwFovzorOd4vHJsVkRgmDS0/lWGpHPz+jwnufeSy/VZQPtcc9CiJFxC30GnnDNjm50yX2gwXg== X-Received: by 2002:a05:600c:10cf:: with SMTP id l15mr2240991wmd.149.1598629524046; Fri, 28 Aug 2020 08:45:24 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id o5sm2707641wmc.33.2020.08.28.08.45.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 28 Aug 2020 08:45:23 -0700 (PDT) Message-Id: <62e8db8b2a8674fb40681478cbae8bbbd6936661.1598629517.git.gitgitgadget@gmail.com> In-Reply-To: References: From: "Derrick Stolee via GitGitGadget" Date: Fri, 28 Aug 2020 15:45:17 +0000 Subject: [PATCH v3 6/6] maintenance: recommended schedule in register/start Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Derrick Stolee , Derrick Stolee , Derrick Stolee Sender: git-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Derrick Stolee The 'git maintenance (register|start)' subcommands add the current repository to the global Git config so maintenance will operate on that repository. It does not specify what maintenance should occur or how often. If a user sets any 'maintenance..schedule' config value, then they have chosen a specific schedule for themselves and Git should respect that. However, in an effort to recommend a good schedule for repositories of all sizes, set new config values for recommended tasks that are safe to run in the background while users run foreground Git commands. These commands are generally everything but the 'gc' task. Author's Note: I feel we should do _something_ to recommend a good schedule to users, but I'm not 100% set on this schedule. This is the schedule we use in Scalar and VFS for Git for very large repositories using the GVFS protocol. While the schedule works in that environment, it is possible that "normal" Git repositories could benefit from something more obvious (such as running 'gc' weekly). However, this patch gives us a place to start a conversation on what we should recommend. For my purposes, Scalar will set these config values so we can always differ from core Git's recommendations. Signed-off-by: Derrick Stolee --- Documentation/git-maintenance.txt | 6 ++++ builtin/gc.c | 46 +++++++++++++++++++++++++++++++ t/t7900-maintenance.sh | 16 +++++++++++ 3 files changed, 68 insertions(+) diff --git a/Documentation/git-maintenance.txt b/Documentation/git-maintenance.txt index 7f8c279fe8..364b3e32bf 100644 --- a/Documentation/git-maintenance.txt +++ b/Documentation/git-maintenance.txt @@ -37,6 +37,12 @@ register:: `maintenance..schedule`. The tasks that are enabled are safe for running in the background without disrupting foreground processes. ++ +If your repository has no 'maintenance..schedule' configuration +values set, then Git will set configuration values to some recommended +settings. These settings disable foreground maintenance while performing +maintenance tasks in the background that will not interrupt foreground Git +operations. run:: Run one or more maintenance tasks. If one or more `--task` options diff --git a/builtin/gc.c b/builtin/gc.c index 9914417e25..5f253d3458 100644 --- a/builtin/gc.c +++ b/builtin/gc.c @@ -1408,6 +1408,49 @@ static int maintenance_run(int argc, const char **argv, const char *prefix) return maintenance_run_tasks(&opts); } +static int has_schedule_config(void) +{ + int i, found = 0; + struct strbuf config_name = STRBUF_INIT; + size_t prefix; + + strbuf_addstr(&config_name, "maintenance."); + prefix = config_name.len; + + for (i = 0; !found && i < TASK__COUNT; i++) { + char *value; + + strbuf_setlen(&config_name, prefix); + strbuf_addf(&config_name, "%s.schedule", tasks[i].name); + + if (!git_config_get_string(config_name.buf, &value)) { + found = 1; + FREE_AND_NULL(value); + } + } + + strbuf_release(&config_name); + return found; +} + +static void set_recommended_schedule(void) +{ + git_config_set("maintenance.auto", "false"); + git_config_set("maintenance.gc.enabled", "false"); + + git_config_set("maintenance.prefetch.enabled", "true"); + git_config_set("maintenance.prefetch.schedule", "hourly"); + + git_config_set("maintenance.commit-graph.enabled", "true"); + git_config_set("maintenance.commit-graph.schedule", "hourly"); + + git_config_set("maintenance.loose-objects.enabled", "true"); + git_config_set("maintenance.loose-objects.schedule", "daily"); + + git_config_set("maintenance.incremental-repack.enabled", "true"); + git_config_set("maintenance.incremental-repack.schedule", "daily"); +} + static int maintenance_register(void) { struct child_process config_set = CHILD_PROCESS_INIT; @@ -1417,6 +1460,9 @@ static int maintenance_register(void) if (!the_repository || !the_repository->gitdir) return 0; + if (!has_schedule_config()) + set_recommended_schedule(); + config_get.git_cmd = 1; strvec_pushl(&config_get.args, "config", "--global", "--get", "maintenance.repo", the_repository->worktree ? the_repository->worktree diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh index 8803fcf621..5a31f3925b 100755 --- a/t/t7900-maintenance.sh +++ b/t/t7900-maintenance.sh @@ -309,7 +309,23 @@ test_expect_success 'register and unregister' ' git config --global --add maintenance.repo /existing1 && git config --global --add maintenance.repo /existing2 && git config --global --get-all maintenance.repo >before && + + # We still have maintenance..schedule config set, + # so this does not update the local schedule + git maintenance register && + test_must_fail git config maintenance.auto && + + # Clear previous maintenance..schedule values + for task in loose-objects commit-graph incremental-repack + do + git config --unset maintenance.$task.schedule || return 1 + done && git maintenance register && + test_cmp_config false maintenance.auto && + test_cmp_config false maintenance.gc.enabled && + test_cmp_config true maintenance.prefetch.enabled && + test_cmp_config hourly maintenance.commit-graph.schedule && + test_cmp_config daily maintenance.incremental-repack.schedule && git config --global --get-all maintenance.repo >actual && cp before after && pwd >>after &&