From: "Đoàn Trần Công Danh" <congdanhqx@gmail.com>
To: "Lénaïc Huard" <lenaic@lhuard.fr>
Cc: git@vger.kernel.org, "Junio C Hamano" <gitster@pobox.com>,
"Derrick Stolee" <dstolee@microsoft.com>,
"Eric Sunshine" <sunshine@sunshineco.com>,
"brian m . carlson" <sandals@crustytoothpaste.net>,
"Bagas Sanjaya" <bagasdotme@gmail.com>,
"Phillip Wood" <phillip.wood123@gmail.com>,
"Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
Subject: Re: [PATCH v2 1/1] maintenance: use systemd timers on Linux
Date: Mon, 10 May 2021 08:20:29 +0700 [thread overview]
Message-ID: <YJiKXRywBhhGXC5Q@danh.dev> (raw)
In-Reply-To: <20210509213217.449489-2-lenaic@lhuard.fr>
On 2021-05-09 23:32:17+0200, Lénaïc Huard <lenaic@lhuard.fr> wrote:
> The existing mechanism for scheduling background maintenance is done
> through cron. On Linux systems managed by systemd, systemd provides an
> alternative to schedule recurring tasks: systemd timers.
>
> +static int systemd_timer_enable_unit(int enable,
> + enum schedule_priority schedule,
> + const char *cmd)
> +{
> + struct child_process child = CHILD_PROCESS_INIT;
> + const char *frequency = get_frequency(schedule);
> +
> + strvec_split(&child.args, cmd);
> + strvec_pushl(&child.args, "--user", enable ? "enable" : "disable",
> + "--now", NULL);
> + strvec_pushf(&child.args, "git-maintenance@%s.timer", frequency);
> +
> + if (start_command(&child))
> + die(_("failed to run systemctl"));
> + return finish_command(&child);
> +}
> +
> +static int systemd_timer_delete_unit_templates(void)
> +{
> + char *filename = xdg_config_home_systemd("git-maintenance@.timer");
> + unlink(filename);
> + free(filename);
> +
> + filename = xdg_config_home_systemd("git-maintenance@.service");
> + unlink(filename);
> + free(filename);
> +
> + return 0;
> +}
> +
> +static int systemd_timer_delete_units(const char *cmd)
> +{
> + return systemd_timer_enable_unit(0, SCHEDULE_HOURLY, cmd) ||
> + systemd_timer_enable_unit(0, SCHEDULE_DAILY, cmd) ||
> + systemd_timer_enable_unit(0, SCHEDULE_WEEKLY, cmd) ||
> + systemd_timer_delete_unit_templates();
> +}
I'm not using any systemd-based distros. However, isn't this try to
enable all systemd's {hourly,daily,weekly} user's timer, then delete
the templates?^W^W^W^W^W^W^W^W^W^W^W^W^W^W^W^W^W^W^W^W^W^W^W^W^W^W^W
Argh, we're disabling those systemd timer units first, by passing 0 as
first argument of systemd_timer_delete_units.
The fact that I read that twice, and still wrote down above reply
makes me think that above code is not self-explanatory enough.
May we switch to something else? Let's say using enum?
> +static int systemd_timer_write_unit_templates(const char *exec_path)
> +{
> + char *filename;
> + FILE *file;
> + const char *unit;
> +
> + filename = xdg_config_home_systemd("git-maintenance@.timer");
> + if (safe_create_leading_directories(filename))
> + die(_("failed to create directories for '%s'"), filename);
This message is used by other codes, less works for translator, nice!
> + file = xfopen(filename, "w");
> + free(filename);
I'm sure if we should use FREE_AND_NULL(filename) instead?
Since, filename will be reused later.
> +
> + unit = "# This file was created and is maintained by Git.\n"
> + "# Any edits made in this file might be replaced in the future\n"
> + "# by a Git command.\n"
> + "\n"
> + "[Unit]\n"
> + "Description=Optimize Git repositories data\n"
> + "\n"
> + "[Timer]\n"
> + "OnCalendar=%i\n"
> + "Persistent=true\n"
> + "\n"
> + "[Install]\n"
> + "WantedBy=timers.target\n";
> + fputs(unit, file);
> + fclose(file);
> +
> + filename = xdg_config_home_systemd("git-maintenance@.service");
> + if (safe_create_leading_directories(filename))
> + die(_("failed to create directories for '%s'"), filename);
> + file = xfopen(filename, "w");
> + free(filename);
> +
> + unit = "# This file was created and is maintained by Git.\n"
> + "# Any edits made in this file might be replaced in the future\n"
> + "# by a Git command.\n"
> + "\n"
> + "[Unit]\n"
> + "Description=Optimize Git repositories data\n"
> + "\n"
> + "[Service]\n"
> + "Type=oneshot\n"
> + "ExecStart=\"%1$s/git\" --exec-path=\"%1$s\" for-each-repo --config=maintenance.repo maintenance run --schedule=%%i\n"
> + "LockPersonality=yes\n"
> + "MemoryDenyWriteExecute=yes\n"
> + "NoNewPrivileges=yes\n"
> + "RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6\n"
> + "RestrictNamespaces=yes\n"
> + "RestrictRealtime=yes\n"
> + "RestrictSUIDSGID=yes\n"
> + "SystemCallArchitectures=native\n"
> + "SystemCallFilter=@system-service\n";
> + fprintf(file, unit, exec_path);
I think others have strong opinion on not using "%1$s",
and prefer simple "%s" and using "exec_path" twice instead.
> + fclose(file);
> +
> + return 0;
> +}
> +
> +static int systemd_timer_setup_units(const char *cmd)
> +{
> + const char *exec_path = git_exec_path();
> +
> + return systemd_timer_write_unit_templates(exec_path) ||
> + systemd_timer_enable_unit(1, SCHEDULE_HOURLY, cmd) ||
> + systemd_timer_enable_unit(1, SCHEDULE_DAILY, cmd) ||
> + systemd_timer_enable_unit(1, SCHEDULE_WEEKLY, cmd);
> +}
> +
> +static int systemd_timer_update_schedule(int run_maintenance, int fd,
> + const char *cmd)
> +{
> + if (run_maintenance)
> + return systemd_timer_setup_units(cmd);
> + else
> + return systemd_timer_delete_units(cmd);
> +}
> +
> +enum scheduler {
> + SCHEDULER_INVALID = -1,
> + SCHEDULER_AUTO = 0,
> + SCHEDULER_CRON = 1,
> + SCHEDULER_SYSTEMD = 2,
> + SCHEDULER_LAUNCHCTL = 3,
> + SCHEDULER_SCHTASKS = 4,
I think explicitly writing down values doesn't make things clearer,
-1 would be nice, not a strong opinion, though.
Anyway, would it be better to move those type declaration to top of
file?
> +};
> +
> +static const struct {
> + int (*is_available)(const char *cmd);
> + int (*update_schedule)(int run_maintenance, int fd, const char *cmd);
> + const char *cmd;
> +} scheduler_fn[] = {
> + [SCHEDULER_CRON] = { is_crontab_available, crontab_update_schedule,
> + "crontab" },
> + [SCHEDULER_SYSTEMD] = { is_systemd_timer_available,
> + systemd_timer_update_schedule, "systemctl" },
> + [SCHEDULER_LAUNCHCTL] = { is_launchctl_available,
> + launchctl_update_schedule, "launchctl" },
> + [SCHEDULER_SCHTASKS] = { is_schtasks_available,
> + schtasks_update_schedule, "schtasks" },
> +};
> +
> +static enum scheduler parse_scheduler(const char *value)
> +{
> + if (!value)
> + return SCHEDULER_INVALID;
> + else if (!strcasecmp(value, "auto"))
> + return SCHEDULER_AUTO;
> + else if (!strcasecmp(value, "cron") || !strcasecmp(value, "crontab"))
> + return SCHEDULER_CRON;
> + else if (!strcasecmp(value, "systemd") ||
> + !strcasecmp(value, "systemd-timer"))
> + return SCHEDULER_SYSTEMD;
> + else if (!strcasecmp(value, "launchctl"))
> + return SCHEDULER_LAUNCHCTL;
> + else if (!strcasecmp(value, "schtasks"))
> + return SCHEDULER_SCHTASKS;
> + else
> + return SCHEDULER_INVALID;
> +}
> +
> +static int maintenance_opt_scheduler(const struct option *opt, const char *arg,
> + int unset)
> +{
> + enum scheduler *scheduler = opt->value;
> +
> + if (unset)
> + die(_("--no-scheduler is not allowed"));
I think it's better to use OPT_CALLBACK_F in the options list and
we will write below code instead:
BUG_ON_OPT_NEG(unset)
> +
> + *scheduler = parse_scheduler(arg);
> +
> + if (*scheduler == SCHEDULER_INVALID)
> + die(_("unrecognized --scheduler argument '%s'"), arg);
Most of other callbacks do this instead:
return error(_("messsage.... '%s'"), arg);
> +
> + return 0;
> +}
> +
> +struct maintenance_start_opts {
> + enum scheduler scheduler;
> +};
> +
> +static void resolve_auto_scheduler(enum scheduler *scheduler)
> +{
> + if (*scheduler != SCHEDULER_AUTO)
> + return;
> +
> #if defined(__APPLE__)
> -static const char platform_scheduler[] = "launchctl";
> + *scheduler = SCHEDULER_LAUNCHCTL;
> + return;
> +
> #elif defined(GIT_WINDOWS_NATIVE)
> -static const char platform_scheduler[] = "schtasks";
> + *scheduler = SCHEDULER_SCHTASKS;
> + return;
> +
> +#elif defined(__linux__)
> + if (is_systemd_timer_available("systemctl"))
> + *scheduler = SCHEDULER_SYSTEMD;
> + else if (is_crontab_available("crontab"))
> + *scheduler = SCHEDULER_CRON;
> + else
> + die(_("neither systemd timers nor crontab are available"));
> + return;
> +
> #else
> -static const char platform_scheduler[] = "crontab";
> + *scheduler = SCHEDULER_CRON;
> + return;
> #endif
> +}
>
> -static int update_background_schedule(int enable)
> +static void validate_scheduler(enum scheduler scheduler)
> {
> - int result;
> - const char *scheduler = platform_scheduler;
> - const char *cmd = scheduler;
> + const char *cmd;
> +
> + if (scheduler == SCHEDULER_INVALID)
> + BUG("invalid scheduler");
> + if (scheduler == SCHEDULER_AUTO)
> + BUG("resolve_auto_scheduler should have been called before");
> +
> + cmd = scheduler_fn[scheduler].cmd;
> + if (!scheduler_fn[scheduler].is_available(cmd))
> + die(_("%s scheduler is not available"), cmd);
> +}
> +
> +static int update_background_schedule(const struct maintenance_start_opts *opts,
> + int enable)
> +{
> + unsigned int i;
> + int res, result = 0;
> + enum scheduler scheduler;
> + const char *cmd = NULL;
> char *testing;
> 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"));
> +
> testing = xstrdup_or_null(getenv("GIT_TEST_MAINT_SCHEDULER"));
> if (testing) {
> char *sep = strchr(testing, ':');
> if (!sep)
> die("GIT_TEST_MAINT_SCHEDULER unparseable: %s", testing);
> *sep = '\0';
> - scheduler = testing;
> + scheduler = parse_scheduler(testing);
> cmd = sep + 1;
> + result = scheduler_fn[scheduler].update_schedule(
> + enable, get_lock_file_fd(&lk), cmd);
> + goto done;
> }
>
> - if (hold_lock_file_for_update(&lk, lock_path, LOCK_NO_DEREF) < 0)
> - return error(_("another process is scheduling background maintenance"));
> -
> - if (!strcmp(scheduler, "launchctl"))
> - result = launchctl_update_schedule(enable, get_lock_file_fd(&lk), cmd);
> - else if (!strcmp(scheduler, "schtasks"))
> - result = schtasks_update_schedule(enable, get_lock_file_fd(&lk), cmd);
> - else if (!strcmp(scheduler, "crontab"))
> - result = crontab_update_schedule(enable, get_lock_file_fd(&lk), cmd);
> - else
> - die("unknown background scheduler: %s", scheduler);
> + for (i = 1; i < ARRAY_SIZE(scheduler_fn); i++) {
> + int enable_scheduler = enable && (opts->scheduler == i);
> + cmd = scheduler_fn[i].cmd;
> + if (!scheduler_fn[i].is_available(cmd))
> + continue;
> + res = scheduler_fn[i].update_schedule(
> + enable_scheduler, get_lock_file_fd(&lk), cmd);
> + if (enable_scheduler)
> + result = res;
> + }
>
> +done:
> rollback_lock_file(&lk);
> free(testing);
> return result;
> }
>
> -static int maintenance_start(void)
> +static const char *const builtin_maintenance_start_usage[] = {
> + N_("git maintenance start [--scheduler=<scheduler>]"), NULL
> +};
> +
> +static int maintenance_start(int argc, const char **argv, const char *prefix)
> {
> + struct maintenance_start_opts opts;
> + struct option builtin_maintenance_start_options[] = {
> + OPT_CALLBACK(
> + 0, "scheduler", &opts.scheduler, N_("scheduler"),
> + N_("scheduler to use to trigger git maintenance run"),
> + maintenance_opt_scheduler),
Following up my comment above, we're better to use:
OPT_CALLBACK_F(0, "scheduler", &opts.scheduler, N_("scheduler"),
N_("............"),
PARSE_OPT_NONEG, maintenance_opt_scheduler),
> + OPT_END()
> + };
> + memset(&opts, 0, sizeof(opts));
> +
> + argc = parse_options(argc, argv, prefix,
> + builtin_maintenance_start_options,
> + builtin_maintenance_start_usage, 0);
> +
> + resolve_auto_scheduler(&opts.scheduler);
> + validate_scheduler(opts.scheduler);
> +
> + if (argc > 0)
> + usage_with_options(builtin_maintenance_start_usage,
> + builtin_maintenance_start_options);
> +
> if (maintenance_register())
> warning(_("failed to add repo to global config"));
> -
> - return update_background_schedule(1);
> + return update_background_schedule(&opts, 1);
> }
>
> static int maintenance_stop(void)
> {
> - return update_background_schedule(0);
> + return update_background_schedule(NULL, 0);
> }
>
> static const char builtin_maintenance_usage[] = N_("git maintenance <subcommand> [<options>]");
> @@ -2027,7 +2354,7 @@ 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();
> + return maintenance_start(argc - 1, argv + 1, prefix);
> if (!strcmp(argv[1], "stop"))
> return maintenance_stop();
> if (!strcmp(argv[1], "register"))
> diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
> index 2412d8c5c0..6e6316cd90 100755
> --- a/t/t7900-maintenance.sh
> +++ b/t/t7900-maintenance.sh
> @@ -20,6 +20,20 @@ test_xmllint () {
> fi
> }
>
> +test_lazy_prereq SYSTEMD_ANALYZE '
> + systemd-analyze --help >out &&
> + grep verify out
> +'
> +
> +test_systemd_analyze_verify () {
> + if test_have_prereq SYSTEMD_ANALYZE
> + then
> + systemd-analyze verify "$@"
> + else
> + true
The "else" leg is not necessary.
> + fi
> +}
> +
> test_expect_success 'help text' '
> test_expect_code 129 git maintenance -h 2>err &&
> test_i18ngrep "usage: git maintenance <subcommand>" err &&
> @@ -615,6 +629,43 @@ test_expect_success 'start and stop Windows maintenance' '
> test_cmp expect args
> '
>
> +test_expect_success 'start and stop Linux/systemd maintenance' '
> + write_script print-args <<-\EOF &&
> + echo $* >>args
To avoid any possible incompatibility with zillion echo implementation
out there. printf should be prefered over echo. Not a in this test
case, however, it costs us nothing anyway.
printf "%s\n" "$*"
> + EOF
> +
> + rm -f args &&
> + GIT_TEST_MAINT_SCHEDULER="systemd:./print-args" git maintenance start &&
> +
> + # start registers the repo
> + git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
> +
> + test_systemd_analyze_verify "$HOME/.config/systemd/user/git-maintenance@.service" &&
> +
> + rm -f expect &&
> + for frequency in hourly daily weekly
> + do
> + echo "--user enable --now git-maintenance@${frequency}.timer" >>expect || return 1
> + done &&
And here, we can have a nicer syntax with printf:
printf "--user enable --now git-maintenance@%s.timer\n" hourly daily weekly >expect &&
With printf, we don't even need "rm -f expect" above.
> + test_cmp expect args &&
> +
> + rm -f args &&
> + GIT_TEST_MAINT_SCHEDULER="systemd:./print-args" git maintenance stop &&
> +
> + # stop does not unregister the repo
> + git config --get --global --fixed-value maintenance.repo "$(pwd)" &&
> +
> + test_path_is_missing "$HOME/.config/systemd/user/git-maintenance@.timer" &&
> + test_path_is_missing "$HOME/.config/systemd/user/git-maintenance@.service" &&
> +
> + rm -f expect &&
> + for frequency in hourly daily weekly
> + do
> + echo "--user disable --now git-maintenance@${frequency}.timer" >>expect || return 1
> + done &&
Ditto.
All of this was written without testing, because I don't have any
systemd based system near my hand, right now.
So, please take it with a grain of salt.
--
Danh
next prev parent reply other threads:[~2021-05-10 1:20 UTC|newest]
Thread overview: 138+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-05-01 14:52 [PATCH] maintenance: use systemd timers on Linux Lénaïc Huard
2021-05-01 20:02 ` brian m. carlson
2021-05-02 5:28 ` Bagas Sanjaya
2021-05-02 6:49 ` Eric Sunshine
2021-05-02 6:45 ` Eric Sunshine
2021-05-02 14:10 ` Phillip Wood
2021-05-05 12:19 ` Đoàn Trần Công Danh
2021-05-05 14:57 ` Phillip Wood
2021-05-05 12:01 ` Ævar Arnfjörð Bjarmason
2021-05-09 22:34 ` Lénaïc Huard
2021-05-10 13:03 ` Ævar Arnfjörð Bjarmason
2021-05-02 11:12 ` Bagas Sanjaya
2021-05-03 12:04 ` Derrick Stolee
2021-05-09 21:32 ` [PATCH v2 0/1] " Lénaïc Huard
2021-05-09 21:32 ` [PATCH v2 1/1] " Lénaïc Huard
2021-05-10 1:20 ` Đoàn Trần Công Danh [this message]
2021-05-10 2:48 ` Eric Sunshine
2021-05-10 6:25 ` Junio C Hamano
2021-05-12 0:29 ` Đoàn Trần Công Danh
2021-05-12 6:59 ` Felipe Contreras
2021-05-12 13:26 ` Phillip Wood
2021-05-12 13:38 ` Phillip Wood
2021-05-12 15:41 ` Đoàn Trần Công Danh
2021-05-10 18:03 ` Phillip Wood
2021-05-10 18:25 ` Eric Sunshine
2021-05-10 20:09 ` Phillip Wood
2021-05-10 20:52 ` Eric Sunshine
2021-06-08 14:55 ` Lénaïc Huard
2021-05-10 19:15 ` Martin Ågren
2021-05-11 14:50 ` Phillip Wood
2021-05-11 17:31 ` Derrick Stolee
2021-05-20 22:13 ` [PATCH v3 0/4] " Lénaïc Huard
2021-05-20 22:13 ` [PATCH v3 1/4] cache.h: rename "xdg_config_home" to "xdg_config_home_git" Lénaïc Huard
2021-05-20 23:44 ` Đoàn Trần Công Danh
2021-05-20 22:13 ` [PATCH v3 2/4] maintenance: introduce ENABLE/DISABLE for code clarity Lénaïc Huard
2021-05-20 22:13 ` [PATCH v3 3/4] maintenance: `git maintenance run` learned `--scheduler=<scheduler>` Lénaïc Huard
2021-05-21 9:52 ` Bagas Sanjaya
2021-05-20 22:13 ` [PATCH v3 4/4] maintenance: optionally use systemd timers on Linux Lénaïc Huard
2021-05-21 9:59 ` Bagas Sanjaya
2021-05-21 16:59 ` Derrick Stolee
2021-05-22 6:57 ` Johannes Schindelin
2021-05-23 18:36 ` Felipe Contreras
2021-05-23 23:27 ` brian m. carlson
2021-05-24 1:18 ` Felipe Contreras
2021-05-24 7:03 ` Ævar Arnfjörð Bjarmason
2021-05-24 15:51 ` Junio C Hamano
2021-05-25 1:50 ` Johannes Schindelin
2021-05-25 11:13 ` Felipe Contreras
2021-05-26 10:29 ` CoC, inclusivity etc. (was "Re: [...] systemd timers on Linux") Ævar Arnfjörð Bjarmason
2021-05-26 16:05 ` Felipe Contreras
2021-05-27 14:24 ` Jeff King
2021-05-27 17:30 ` Felipe Contreras
2021-05-27 23:58 ` Junio C Hamano
2021-05-28 14:44 ` Phillip Susi
2021-05-30 21:58 ` Jeff King
2021-05-24 17:52 ` [PATCH v3 4/4] maintenance: optionally use systemd timers on Linux Felipe Contreras
2021-05-24 7:15 ` [PATCH v4 0/4] add support for " Lénaïc Huard
2021-05-24 7:15 ` [PATCH v4 1/4] cache.h: Introduce a generic "xdg_config_home_for(…)" function Lénaïc Huard
2021-05-24 9:33 ` Phillip Wood
2021-05-24 12:23 ` Đoàn Trần Công Danh
2021-05-24 7:15 ` [PATCH v4 2/4] maintenance: introduce ENABLE/DISABLE for code clarity Lénaïc Huard
2021-05-24 9:41 ` Phillip Wood
2021-05-24 12:36 ` Đoàn Trần Công Danh
2021-05-25 7:18 ` Lénaïc Huard
2021-05-25 8:02 ` Junio C Hamano
2021-05-24 9:47 ` Ævar Arnfjörð Bjarmason
2021-05-24 7:15 ` [PATCH v4 3/4] maintenance: `git maintenance run` learned `--scheduler=<scheduler>` Lénaïc Huard
2021-05-24 10:12 ` Phillip Wood
2021-05-30 6:39 ` Lénaïc Huard
2021-05-30 10:16 ` Phillip Wood
2021-05-24 7:15 ` [PATCH v4 4/4] maintenance: add support for systemd timers on Linux Lénaïc Huard
2021-05-24 9:55 ` Ævar Arnfjörð Bjarmason
2021-05-24 16:39 ` Eric Sunshine
2021-05-24 18:08 ` Felipe Contreras
2021-05-26 10:26 ` Phillip Wood
2021-05-24 9:04 ` [PATCH v4 0/4] " Junio C Hamano
2021-06-08 13:39 ` [PATCH v5 0/3] " Lénaïc Huard
2021-06-08 13:39 ` [PATCH v5 1/3] cache.h: Introduce a generic "xdg_config_home_for(…)" function Lénaïc Huard
2021-06-08 13:39 ` [PATCH v5 2/3] maintenance: `git maintenance run` learned `--scheduler=<scheduler>` Lénaïc Huard
2021-06-08 13:40 ` [PATCH v5 3/3] maintenance: add support for systemd timers on Linux Lénaïc Huard
2021-06-09 9:34 ` Jeff King
2021-06-09 15:01 ` Phillip Wood
2021-06-09 0:21 ` [PATCH v5 0/3] " Junio C Hamano
2021-06-09 14:54 ` Phillip Wood
2021-06-12 16:50 ` [PATCH v6 0/3] maintenance: " Lénaïc Huard
2021-06-12 16:50 ` [PATCH v6 1/3] cache.h: Introduce a generic "xdg_config_home_for(…)" function Lénaïc Huard
2021-06-12 16:50 ` [PATCH v6 2/3] maintenance: `git maintenance run` learned `--scheduler=<scheduler>` Lénaïc Huard
2021-06-14 4:36 ` Eric Sunshine
2021-06-16 18:12 ` Derrick Stolee
2021-06-17 4:11 ` Eric Sunshine
2021-06-17 14:26 ` Phillip Wood
2021-07-02 15:04 ` Lénaïc Huard
2021-06-12 16:50 ` [PATCH v6 3/3] maintenance: add support for systemd timers on Linux Lénaïc Huard
2021-07-02 14:25 ` [PATCH v7 0/3] " Lénaïc Huard
2021-07-02 14:25 ` [PATCH v7 1/3] cache.h: Introduce a generic "xdg_config_home_for(…)" function Lénaïc Huard
2021-07-02 14:25 ` [PATCH v7 2/3] maintenance: `git maintenance run` learned `--scheduler=<scheduler>` Lénaïc Huard
2021-07-06 19:56 ` Ævar Arnfjörð Bjarmason
2021-07-06 20:52 ` Junio C Hamano
2021-07-13 0:15 ` Jeff King
2021-07-13 2:22 ` Eric Sunshine
2021-07-13 3:56 ` Jeff King
2021-07-13 5:17 ` Eric Sunshine
2021-07-13 7:04 ` Bagas Sanjaya
2021-07-06 21:18 ` Felipe Contreras
2021-08-23 20:06 ` Lénaïc Huard
2021-08-23 22:30 ` Junio C Hamano
2021-07-02 14:25 ` [PATCH v7 3/3] maintenance: add support for systemd timers on Linux Lénaïc Huard
2021-07-06 20:03 ` Ævar Arnfjörð Bjarmason
2021-07-02 18:18 ` [PATCH v7 0/3] " Junio C Hamano
2021-07-06 13:18 ` Phillip Wood
2021-08-23 20:40 ` [PATCH v8 " Lénaïc Huard
2021-08-23 20:40 ` [PATCH v8 1/3] cache.h: Introduce a generic "xdg_config_home_for(…)" function Lénaïc Huard
2021-08-23 20:40 ` [PATCH v8 2/3] maintenance: `git maintenance run` learned `--scheduler=<scheduler>` Lénaïc Huard
2021-08-24 17:45 ` Derrick Stolee
2021-08-23 20:40 ` [PATCH v8 3/3] maintenance: add support for systemd timers on Linux Lénaïc Huard
2021-08-24 17:45 ` Derrick Stolee
2021-08-24 17:47 ` [PATCH v8 0/3] " Derrick Stolee
2021-08-27 21:02 ` [PATCH v9 " Lénaïc Huard
2021-08-27 21:02 ` [PATCH v9 1/3] cache.h: Introduce a generic "xdg_config_home_for(…)" function Lénaïc Huard
2021-08-27 21:02 ` [PATCH v9 2/3] maintenance: `git maintenance run` learned `--scheduler=<scheduler>` Lénaïc Huard
2021-08-27 23:54 ` Ramsay Jones
2021-08-27 21:02 ` [PATCH v9 3/3] maintenance: add support for systemd timers on Linux Lénaïc Huard
2021-09-04 20:54 ` [PATCH v10 0/3] " Lénaïc Huard
2021-09-04 20:54 ` [PATCH v10 1/3] cache.h: Introduce a generic "xdg_config_home_for(…)" function Lénaïc Huard
2021-09-04 20:54 ` [PATCH v10 2/3] maintenance: `git maintenance run` learned `--scheduler=<scheduler>` Lénaïc Huard
2021-09-04 20:55 ` [PATCH v10 3/3] maintenance: add support for systemd timers on Linux Lénaïc Huard
2021-09-07 16:48 ` [PATCH v10 0/3] " Derrick Stolee
2021-09-08 11:44 ` Derrick Stolee
2021-09-09 5:52 ` Lénaïc Huard
2021-09-09 19:55 ` Derrick Stolee
2021-09-27 12:50 ` Ævar Arnfjörð Bjarmason
2021-09-27 21:44 ` Lénaïc Huard
2021-08-17 17:22 ` [PATCH v5 0/3] " Derrick Stolee
2021-08-17 19:43 ` Phillip Wood
2021-08-17 20:29 ` Derrick Stolee
2021-08-18 5:56 ` Lénaïc Huard
2021-08-18 13:28 ` Derrick Stolee
2021-08-18 18:23 ` Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=YJiKXRywBhhGXC5Q@danh.dev \
--to=congdanhqx@gmail.com \
--cc=avarab@gmail.com \
--cc=bagasdotme@gmail.com \
--cc=dstolee@microsoft.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=lenaic@lhuard.fr \
--cc=phillip.wood123@gmail.com \
--cc=sandals@crustytoothpaste.net \
--cc=sunshine@sunshineco.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).