From: Patrick Steinhardt <ps@pks.im>
To: Matthew Hughes <matthewhughes934@gmail.com>
Cc: git@vger.kernel.org, Derrick Stolee <stolee@gmail.com>
Subject: Re: [RFC PATCH 1/1] maintenance: add config option for config-file
Date: Fri, 19 Dec 2025 08:18:45 +0100 [thread overview]
Message-ID: <aUT8Vcevf8WiQgn0@pks.im> (raw)
In-Reply-To: <20251218184751.31209-2-matthewhughes934@gmail.com>
On Thu, Dec 18, 2025 at 06:48:19PM +0000, Matthew Hughes wrote:
> This is to allow splitting out this configuration from the global config
> file, e.g.:
>
> # in ~/.config/git/config
> [include]
> path = maintenance.config
> [maintenance]
> # use a separate files for reads/writes from
> # 'git maintenance {un,}register'
> configFile = ~/.config/git/maintenance.config
>
> # in ~/.config/git/maintenance.config
> [maintenance]
> repo = /path/to/some/repo
> repo = /path/to/another/repo
>
> My motivation for this is that I track my global config in git, so I'd
> like to avoid changes in there that depend on specific repos/workflows
> that I'm working with.
I think the idea is quite sensible, and I understand the need to split
up static configuration from dynamic one. One part I'm unsure about
though is the explicit need to use "include.path" for this. Ideally,
git-maintenance(1) should by itself know to include the path that the
user has configured in "maintenance.configFile".
> diff --git a/builtin/gc.c b/builtin/gc.c
> index 92c6e7b954..257cceecf6 100644
> --- a/builtin/gc.c
> +++ b/builtin/gc.c
> @@ -2124,6 +2124,10 @@ static int maintenance_register(int argc, const char **argv, const char *prefix,
> usage_with_options(builtin_maintenance_register_usage,
> options);
>
> + if (config_file == NULL) {
> + repo_config_get_pathname(the_repository, "maintenance.configFile", &config_file);
> + }
Note that in our codebase this would typically be written as:
if (!config_file)
repo_config_get_pathname(the_repository, "maintenance.configFile", &config_file);
Note the missing curly braces around a single-line statement as well as
the implicit check for NULL.
It's nice that we only need a two-line change here to make this work.
> @@ -2194,6 +2198,10 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
> usage_with_options(builtin_maintenance_unregister_usage,
> options);
>
> + if (config_file == NULL) {
> + repo_config_get_pathname(the_repository, "maintenance.configFile", &config_file);
> + }
Okay, this is the equivalent for unregistering maintenance. Makes senes.
So these both are straight-forward. The question is whether we can also
easily teach scheduled maintenance to respect `maintenance.configFile`
so that the user doesn't have to manually include the configured file.
I think the answer is "not quite".
The services that scheduled maintenance writes use git-for-each-repo(1)
to iterate through all repositories. We basically execute that command
via `git for-each-repo --config=maintenance.repo -- git maintenance
run --schedule=%%i`. But that command does not have a way to have it
read the configuration from a different file.
I think adding such a feature shouldn't be that hard though. You can use
the below (completely untested) patch as a starter for this. But once we
had such a feature we'd only have to adapt how we write the services
files to pass the new flag in case "maintenance.configFile" is set.
There's two questions in this context:
- Do we already know to rewrite the service files in case the commands
that Git would write change?
- Do we need to migrate any of the preexisting keys that exist in the
global configuration?
Also Cc'ing Stolee for input.
Thanks!
Patrick
-- >8 --
diff --git a/builtin/for-each-repo.c b/builtin/for-each-repo.c
index 325a7925f1..874f98ced6 100644
--- a/builtin/for-each-repo.c
+++ b/builtin/for-each-repo.c
@@ -1,6 +1,7 @@
#define USE_THE_REPOSITORY_VARIABLE
#include "builtin.h"
+#include "abspath.h"
#include "config.h"
#include "gettext.h"
#include "parse-options.h"
@@ -39,11 +40,16 @@ int cmd_for_each_repo(int argc,
int keep_going = 0;
int result = 0;
const struct string_list *values;
+ struct config_set configset = { 0 };
+ const char *config_file = NULL;
+ char *config_file_to_free = NULL;
int err;
const struct option options[] = {
OPT_STRING(0, "config", &config_key, N_("config"),
N_("config key storing a list of repository paths")),
+ OPT_STRING(0, "file", &config_file, N_("file"),
+ N_("use given config file")),
OPT_BOOL(0, "keep-going", &keep_going,
N_("keep going even if command fails in a repository")),
OPT_END()
@@ -55,21 +61,38 @@ int cmd_for_each_repo(int argc,
if (!config_key)
die(_("missing --config=<config>"));
- err = repo_config_get_string_multi(the_repository, config_key, &values);
+ if (config_file) {
+ if (!is_absolute_path(config_file) && prefix)
+ config_file = config_file_to_free = prefix_filename(prefix, config_file);
+
+ git_configset_init(&configset);
+ err = git_configset_add_file(&configset, config_file);
+ if (err < 0)
+ die_errno(_("config file could not be read: '%s'"), config_file);
+
+ err = git_configset_get_string_multi(&configset, config_key, &values);
+ } else {
+ err = repo_config_get_string_multi(the_repository, config_key, &values);
+ }
if (err < 0)
usage_msg_optf(_("got bad config --config=%s"),
for_each_repo_usage, options, config_key);
else if (err)
- return 0;
+ goto out;
for (size_t i = 0; i < values->nr; i++) {
int ret = run_command_on_repo(values->items[i].string, argc, argv);
if (ret) {
- if (!keep_going)
- return ret;
+ if (!keep_going) {
+ result = ret;
+ goto out;
+ }
result = 1;
}
}
+out:
+ git_configset_clear(&configset);
+ free(config_file_to_free);
return result;
}
next prev parent reply other threads:[~2025-12-19 7:18 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-12-18 18:48 [RFC PATCH 0/1] maintenance: add config option for config-file Matthew Hughes
2025-12-18 18:48 ` [RFC PATCH 1/1] " Matthew Hughes
2025-12-19 7:18 ` Patrick Steinhardt [this message]
2025-12-19 8:27 ` Junio C Hamano
2025-12-22 8:26 ` Matthew Hughes
2025-12-22 21:51 ` D. Ben Knoble
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
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aUT8Vcevf8WiQgn0@pks.im \
--to=ps@pks.im \
--cc=git@vger.kernel.org \
--cc=matthewhughes934@gmail.com \
--cc=stolee@gmail.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.
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 NNTP newsgroup(s).