Skip to content

Commit eb06ff9

Browse files
committed
Merge branch 'nd/config-move-to' into pu
* nd/config-move-to: config.h: fix hdr-check warnings config: add --move-to config: factor out set_config_source_file() config: use OPT_FILENAME() config.c: add repo_config_set_worktree_gently() worktree.c: add get_worktree_config() config.c: avoid git_path() in do_git_config_sequence()
2 parents 49ea864 + 59b12ae commit eb06ff9

File tree

8 files changed

+331
-78
lines changed

8 files changed

+331
-78
lines changed

Documentation/git-config.txt

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ SYNOPSIS
2020
'git config' [<file-option>] --unset-all name [value_regex]
2121
'git config' [<file-option>] --rename-section old_name new_name
2222
'git config' [<file-option>] --remove-section name
23+
'git config' [<file-option>] --move-to name
24+
'git config' [<file-option>] --move-regexp-to name-regexp
25+
'git config' [<file-option>] --move-glob-to name-glob
2326
'git config' [<file-option>] [--show-origin] [-z|--null] [--name-only] -l | --list
2427
'git config' [<file-option>] --get-color name [default]
2528
'git config' [<file-option>] --get-colorbool name [stdout-is-tty]
@@ -161,6 +164,15 @@ See also <<FILES>>.
161164
--unset-all::
162165
Remove all lines matching the key from config file.
163166

167+
--move-to::
168+
--move-regexp-to::
169+
--move-glob-to::
170+
Move a config variable (or multiple variables matching the
171+
given regular expression or glob pattern) to a new file. Any
172+
option about the config file location after `--move-to` or
173+
`--move-to-regexp` specifies the move destination. Existing
174+
config of the same name remains.
175+
164176
-l::
165177
--list::
166178
List all variables set in config file, along with their values.

Documentation/git-worktree.txt

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,13 +252,17 @@ rev-parse --git-path config.worktree`. You can add or update
252252
configuration in this file with `git config --worktree`. Older Git
253253
versions will refuse to access repositories with this extension.
254254

255-
Note that in this file, the exception for `core.bare` and `core.worktree`
256-
is gone. If you have them in $GIT_DIR/config before, you must move
257-
them to the `config.worktree` of the main working tree. You may also
258-
take this opportunity to review and move other configuration that you
259-
do not want to share to all working trees:
255+
Note that in this file, the exception for `core.bare` and
256+
`core.worktree` is gone. If you have them in $GIT_DIR/config before,
257+
you must move them to the `config.worktree` of the main working tree.
260258

261-
- `core.worktree` and `core.bare` should never be shared
259+
------------
260+
$ git config --local --move-to --worktree core.bare
261+
$ git config --local --move-to --worktree core.worktree
262+
------------
263+
264+
You may also take this opportunity to review and move other
265+
configuration that you do not want to share to all working trees:
262266

263267
- `core.sparseCheckout` is recommended per working tree, unless you
264268
are sure you always use sparse checkout for all working trees.

builtin/config.c

Lines changed: 180 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ static char term = '\n';
2626

2727
static int use_global_config, use_system_config, use_local_config;
2828
static int use_worktree_config;
29+
static struct git_config_source move_source;
2930
static struct git_config_source given_config_source;
3031
static int actions, type;
3132
static char *default_value;
@@ -50,6 +51,9 @@ static int show_origin;
5051
#define ACTION_GET_COLOR (1<<13)
5152
#define ACTION_GET_COLORBOOL (1<<14)
5253
#define ACTION_GET_URLMATCH (1<<15)
54+
#define ACTION_MOVE (1<<16)
55+
#define ACTION_MOVE_REGEXP (1<<17)
56+
#define ACTION_MOVE_GLOB (1<<18)
5357

5458
/*
5559
* The actions "ACTION_LIST | ACTION_GET_*" which may produce more than
@@ -71,6 +75,64 @@ static int show_origin;
7175

7276
static NORETURN void usage_builtin_config(void);
7377

78+
static void set_config_source_file(void)
79+
{
80+
int nongit = !startup_info->have_repository;
81+
82+
if (use_global_config + use_system_config + use_local_config +
83+
use_worktree_config +
84+
!!given_config_source.file + !!given_config_source.blob > 1)
85+
die(_("only one config file at a time"));
86+
87+
if (use_local_config && nongit)
88+
die(_("--local can only be used inside a git repository"));
89+
90+
if (given_config_source.blob && nongit)
91+
die(_("--blob can only be used inside a git repository"));
92+
93+
if (given_config_source.file &&
94+
!strcmp(given_config_source.file, "-")) {
95+
given_config_source.file = NULL;
96+
given_config_source.use_stdin = 1;
97+
}
98+
99+
if (use_global_config) {
100+
char *user_config = expand_user_path("~/.gitconfig", 0);
101+
char *xdg_config = xdg_config_home("config");
102+
103+
if (!user_config)
104+
/*
105+
* It is unknown if HOME/.gitconfig exists, so
106+
* we do not know if we should write to XDG
107+
* location; error out even if XDG_CONFIG_HOME
108+
* is set and points at a sane location.
109+
*/
110+
die(_("$HOME not set"));
111+
112+
if (access_or_warn(user_config, R_OK, 0) &&
113+
xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
114+
given_config_source.file = xdg_config;
115+
free(user_config);
116+
} else {
117+
given_config_source.file = user_config;
118+
free(xdg_config);
119+
}
120+
}
121+
else if (use_system_config)
122+
given_config_source.file = git_etc_gitconfig();
123+
else if (use_local_config)
124+
given_config_source.file = git_pathdup("config");
125+
else if (use_worktree_config) {
126+
given_config_source.file = get_worktree_config(the_repository);
127+
if (!given_config_source.file)
128+
die(_("--worktree cannot be used with multiple "
129+
"working trees unless the config\n"
130+
"extension worktreeConfig is enabled. "
131+
"Please read \"CONFIGURATION FILE\"\n"
132+
"section in \"git help worktree\" for details"));
133+
}
134+
}
135+
74136
static int option_parse_type(const struct option *opt, const char *arg,
75137
int unset)
76138
{
@@ -120,13 +182,32 @@ static int option_parse_type(const struct option *opt, const char *arg,
120182
return 0;
121183
}
122184

185+
static int option_move_cb(const struct option *opt,
186+
const char *arg, int unset)
187+
{
188+
BUG_ON_OPT_NEG(unset);
189+
BUG_ON_OPT_ARG(arg);
190+
191+
set_config_source_file();
192+
memcpy(&move_source, &given_config_source, sizeof(move_source));
193+
194+
memset(&given_config_source, 0, sizeof(given_config_source));
195+
use_global_config = 0;
196+
use_system_config = 0;
197+
use_local_config = 0;
198+
use_worktree_config = 0;
199+
200+
actions = opt->defval;
201+
return 0;
202+
}
203+
123204
static struct option builtin_config_options[] = {
124205
OPT_GROUP(N_("Config file location")),
125206
OPT_BOOL(0, "global", &use_global_config, N_("use global config file")),
126207
OPT_BOOL(0, "system", &use_system_config, N_("use system config file")),
127208
OPT_BOOL(0, "local", &use_local_config, N_("use repository config file")),
128209
OPT_BOOL(0, "worktree", &use_worktree_config, N_("use per-worktree config file")),
129-
OPT_STRING('f', "file", &given_config_source.file, N_("file"), N_("use given config file")),
210+
OPT_FILENAME('f', "file", &given_config_source.file, N_("use given config file")),
130211
OPT_STRING(0, "blob", &given_config_source.blob, N_("blob-id"), N_("read config from given blob object")),
131212
OPT_GROUP(N_("Action")),
132213
OPT_BIT(0, "get", &actions, N_("get value: name [value-regex]"), ACTION_GET),
@@ -139,6 +220,18 @@ static struct option builtin_config_options[] = {
139220
OPT_BIT(0, "unset-all", &actions, N_("remove all matches: name [value-regex]"), ACTION_UNSET_ALL),
140221
OPT_BIT(0, "rename-section", &actions, N_("rename section: old-name new-name"), ACTION_RENAME_SECTION),
141222
OPT_BIT(0, "remove-section", &actions, N_("remove a section: name"), ACTION_REMOVE_SECTION),
223+
{ OPTION_CALLBACK, 0, "move-to", NULL, NULL,
224+
N_("move a variable to a different config file"),
225+
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
226+
option_move_cb, ACTION_MOVE },
227+
{ OPTION_CALLBACK, 0, "move-regexp-to", NULL, NULL,
228+
N_("move matching variables to a different config file"),
229+
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
230+
option_move_cb, ACTION_MOVE_REGEXP },
231+
{ OPTION_CALLBACK, 0, "move-glob-to", NULL, NULL,
232+
N_("move matching variables to a different config file"),
233+
PARSE_OPT_NONEG | PARSE_OPT_NOARG,
234+
option_move_cb, ACTION_MOVE_GLOB },
142235
OPT_BIT('l', "list", &actions, N_("list all"), ACTION_LIST),
143236
OPT_BIT('e', "edit", &actions, N_("open an editor"), ACTION_EDIT),
144237
OPT_BIT(0, "get-color", &actions, N_("find the color configured: slot [default]"), ACTION_GET_COLOR),
@@ -369,6 +462,84 @@ static int get_value(const char *key_, const char *regex_)
369462
return ret;
370463
}
371464

465+
struct move_config_cb {
466+
struct string_list keys;
467+
const char *key;
468+
regex_t key_re;
469+
};
470+
471+
static int collect_move_config(const char *key, const char *value, void *cb)
472+
{
473+
struct move_config_cb *data = cb;
474+
475+
switch (actions) {
476+
case ACTION_MOVE:
477+
if (strcasecmp(data->key, key))
478+
return 0;
479+
break;
480+
case ACTION_MOVE_REGEXP:
481+
if (regexec(&data->key_re, key, 0, NULL, 0))
482+
return 0;
483+
break;
484+
case ACTION_MOVE_GLOB:
485+
if (wildmatch(data->key, key, WM_CASEFOLD))
486+
return 0;
487+
break;
488+
default:
489+
BUG("action %d cannot get here", actions);
490+
}
491+
492+
string_list_append(&data->keys, key)->util = xstrdup(value);
493+
return 0;
494+
}
495+
496+
static int move_config(const char *key)
497+
{
498+
struct move_config_cb cb;
499+
int i, ret = 0;
500+
501+
config_options.respect_includes = 0;
502+
if (!move_source.file && !move_source.use_stdin && !move_source.blob)
503+
die(_("unknown config source"));
504+
505+
string_list_init(&cb.keys, 1);
506+
cb.key = key;
507+
if (actions == ACTION_MOVE_REGEXP &&
508+
regcomp(&cb.key_re, key, REG_EXTENDED | REG_ICASE))
509+
die(_("invalid key pattern: %s"), key);
510+
511+
config_with_options(collect_move_config, &cb,
512+
&move_source, &config_options);
513+
514+
for (i = 0; i < cb.keys.nr && !ret; i++) {
515+
const char *key = cb.keys.items[i].string;
516+
const char *value = cb.keys.items[i].util;
517+
const char *dest = given_config_source.file;
518+
519+
ret = git_config_set_multivar_in_file_gently(
520+
dest, key, value, CONFIG_REGEX_NONE, 0);
521+
}
522+
523+
/*
524+
* OK all keys have been copied successfully, time to delete
525+
* old ones
526+
*/
527+
if (!ret && move_source.file) {
528+
for (i = 0; i < cb.keys.nr; i++) {
529+
const char *key = cb.keys.items[i].string;
530+
const char *src = move_source.file;
531+
532+
git_config_set_multivar_in_file_gently(
533+
src, key, NULL, NULL, 1);
534+
}
535+
}
536+
537+
string_list_clear(&cb.keys, 1);
538+
if (actions == ACTION_MOVE_REGEXP)
539+
regfree(&cb.key_re);
540+
return ret;
541+
}
542+
372543
static char *normalize_value(const char *key, const char *value)
373544
{
374545
if (!value)
@@ -605,69 +776,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
605776
builtin_config_usage,
606777
PARSE_OPT_STOP_AT_NON_OPTION);
607778

608-
if (use_global_config + use_system_config + use_local_config +
609-
use_worktree_config +
610-
!!given_config_source.file + !!given_config_source.blob > 1) {
611-
error(_("only one config file at a time"));
612-
usage_builtin_config();
613-
}
614-
615-
if (use_local_config && nongit)
616-
die(_("--local can only be used inside a git repository"));
617-
618-
if (given_config_source.blob && nongit)
619-
die(_("--blob can only be used inside a git repository"));
620-
621-
if (given_config_source.file &&
622-
!strcmp(given_config_source.file, "-")) {
623-
given_config_source.file = NULL;
624-
given_config_source.use_stdin = 1;
625-
}
626-
627-
if (use_global_config) {
628-
char *user_config = expand_user_path("~/.gitconfig", 0);
629-
char *xdg_config = xdg_config_home("config");
630-
631-
if (!user_config)
632-
/*
633-
* It is unknown if HOME/.gitconfig exists, so
634-
* we do not know if we should write to XDG
635-
* location; error out even if XDG_CONFIG_HOME
636-
* is set and points at a sane location.
637-
*/
638-
die(_("$HOME not set"));
639-
640-
if (access_or_warn(user_config, R_OK, 0) &&
641-
xdg_config && !access_or_warn(xdg_config, R_OK, 0)) {
642-
given_config_source.file = xdg_config;
643-
free(user_config);
644-
} else {
645-
given_config_source.file = user_config;
646-
free(xdg_config);
647-
}
648-
}
649-
else if (use_system_config)
650-
given_config_source.file = git_etc_gitconfig();
651-
else if (use_local_config)
652-
given_config_source.file = git_pathdup("config");
653-
else if (use_worktree_config) {
654-
struct worktree **worktrees = get_worktrees(0);
655-
if (repository_format_worktree_config)
656-
given_config_source.file = git_pathdup("config.worktree");
657-
else if (worktrees[0] && worktrees[1])
658-
die(_("--worktree cannot be used with multiple "
659-
"working trees unless the config\n"
660-
"extension worktreeConfig is enabled. "
661-
"Please read \"CONFIGURATION FILE\"\n"
662-
"section in \"git help worktree\" for details"));
663-
else
664-
given_config_source.file = git_pathdup("config");
665-
free_worktrees(worktrees);
666-
} else if (given_config_source.file) {
667-
if (!is_absolute_path(given_config_source.file) && prefix)
668-
given_config_source.file =
669-
prefix_filename(prefix, given_config_source.file);
670-
}
779+
set_config_source_file();
671780

672781
if (respect_includes_opt == -1)
673782
config_options.respect_includes = !given_config_source.file;
@@ -867,6 +976,13 @@ int cmd_config(int argc, const char **argv, const char *prefix)
867976
color_stdout_is_tty = git_config_bool("command line", argv[1]);
868977
return get_colorbool(argv[0], argc == 2);
869978
}
979+
else if (actions == ACTION_MOVE ||
980+
actions == ACTION_MOVE_REGEXP ||
981+
actions == ACTION_MOVE_GLOB) {
982+
check_write();
983+
check_argc(argc, 1, 1);
984+
return move_config(argv[0]);
985+
}
870986

871987
return 0;
872988
}

0 commit comments

Comments
 (0)