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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.