Skip to content

Commit 3256584

Browse files
committed
Merge branch 'rs/config-comment'
"git config" learned "--comment=<message>" option to leave a comment immediately after the "variable = value" on the same line in the configuration file. * rs/config-comment: config: allow tweaking whitespace between value and comment config: fix --comment formatting config: add --comment option to add a comment
2 parents 7774cfe + 31399a6 commit 3256584

File tree

12 files changed

+152
-46
lines changed

12 files changed

+152
-46
lines changed

Documentation/git-config.txt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ git-config - Get and set repository or global options
99
SYNOPSIS
1010
--------
1111
[verse]
12-
'git config' [<file-option>] [--type=<type>] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] <name> [<value> [<value-pattern>]]
13-
'git config' [<file-option>] [--type=<type>] --add <name> <value>
14-
'git config' [<file-option>] [--type=<type>] [--fixed-value] --replace-all <name> <value> [<value-pattern>]
12+
'git config' [<file-option>] [--type=<type>] [--comment=<message>] [--fixed-value] [--show-origin] [--show-scope] [-z|--null] <name> [<value> [<value-pattern>]]
13+
'git config' [<file-option>] [--type=<type>] [--comment=<message>] --add <name> <value>
14+
'git config' [<file-option>] [--type=<type>] [--comment=<message>] [--fixed-value] --replace-all <name> <value> [<value-pattern>]
1515
'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] --get <name> [<value-pattern>]
1616
'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] --get-all <name> [<value-pattern>]
1717
'git config' [<file-option>] [--type=<type>] [--show-origin] [--show-scope] [-z|--null] [--fixed-value] [--name-only] --get-regexp <name-regex> [<value-pattern>]
@@ -87,6 +87,18 @@ OPTIONS
8787
values. This is the same as providing '^$' as the `value-pattern`
8888
in `--replace-all`.
8989

90+
--comment <message>::
91+
Append a comment at the end of new or modified lines.
92+
93+
If _<message>_ begins with one or more whitespaces followed
94+
by "#", it is used as-is. If it begins with "#", a space is
95+
prepended before it is used. Otherwise, a string " # " (a
96+
space followed by a hash followed by a space) is prepended
97+
to it. And the resulting string is placed immediately after
98+
the value defined for the variable. The _<message>_ must
99+
not contain linefeed characters (no multi-line comments are
100+
permitted).
101+
90102
--get::
91103
Get the value for a given key (optionally filtered by a regex
92104
matching the value). Returns error code 1 if the key was not

builtin/config.c

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ static struct config_options config_options;
4444
static int show_origin;
4545
static int show_scope;
4646
static int fixed_value;
47+
static const char *comment;
4748

4849
#define ACTION_GET (1<<0)
4950
#define ACTION_GET_ALL (1<<1)
@@ -173,6 +174,7 @@ static struct option builtin_config_options[] = {
173174
OPT_BOOL(0, "show-origin", &show_origin, N_("show origin of config (file, standard input, blob, command line)")),
174175
OPT_BOOL(0, "show-scope", &show_scope, N_("show scope of config (worktree, local, global, system, command)")),
175176
OPT_STRING(0, "default", &default_value, N_("value"), N_("with --get, use default value when missing entry")),
177+
OPT_STRING(0, "comment", &comment, N_("value"), N_("human-readable comment string (# will be prepended as needed)")),
176178
OPT_END(),
177179
};
178180

@@ -797,6 +799,12 @@ int cmd_config(int argc, const char **argv, const char *prefix)
797799
usage_builtin_config();
798800
}
799801

802+
if (comment &&
803+
!(actions & (ACTION_ADD|ACTION_SET|ACTION_SET_ALL|ACTION_REPLACE_ALL))) {
804+
error(_("--comment is only applicable to add/set/replace operations"));
805+
usage_builtin_config();
806+
}
807+
800808
/* check usage of --fixed-value */
801809
if (fixed_value) {
802810
int allowed_usage = 0;
@@ -833,6 +841,8 @@ int cmd_config(int argc, const char **argv, const char *prefix)
833841
flags |= CONFIG_FLAGS_FIXED_VALUE;
834842
}
835843

844+
comment = git_config_prepare_comment_string(comment);
845+
836846
if (actions & PAGING_ACTIONS)
837847
setup_auto_pager("config", 1);
838848

@@ -880,7 +890,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
880890
check_write();
881891
check_argc(argc, 2, 2);
882892
value = normalize_value(argv[0], argv[1], &default_kvi);
883-
ret = git_config_set_in_file_gently(given_config_source.file, argv[0], value);
893+
ret = git_config_set_in_file_gently(given_config_source.file, argv[0], comment, value);
884894
if (ret == CONFIG_NOTHING_SET)
885895
error(_("cannot overwrite multiple values with a single value\n"
886896
" Use a regexp, --add or --replace-all to change %s."), argv[0]);
@@ -891,7 +901,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
891901
value = normalize_value(argv[0], argv[1], &default_kvi);
892902
ret = git_config_set_multivar_in_file_gently(given_config_source.file,
893903
argv[0], value, argv[2],
894-
flags);
904+
comment, flags);
895905
}
896906
else if (actions == ACTION_ADD) {
897907
check_write();
@@ -900,15 +910,15 @@ int cmd_config(int argc, const char **argv, const char *prefix)
900910
ret = git_config_set_multivar_in_file_gently(given_config_source.file,
901911
argv[0], value,
902912
CONFIG_REGEX_NONE,
903-
flags);
913+
comment, flags);
904914
}
905915
else if (actions == ACTION_REPLACE_ALL) {
906916
check_write();
907917
check_argc(argc, 2, 3);
908918
value = normalize_value(argv[0], argv[1], &default_kvi);
909919
ret = git_config_set_multivar_in_file_gently(given_config_source.file,
910920
argv[0], value, argv[2],
911-
flags | CONFIG_FLAGS_MULTI_REPLACE);
921+
comment, flags | CONFIG_FLAGS_MULTI_REPLACE);
912922
}
913923
else if (actions == ACTION_GET) {
914924
check_argc(argc, 1, 2);
@@ -936,17 +946,17 @@ int cmd_config(int argc, const char **argv, const char *prefix)
936946
if (argc == 2)
937947
return git_config_set_multivar_in_file_gently(given_config_source.file,
938948
argv[0], NULL, argv[1],
939-
flags);
949+
NULL, flags);
940950
else
941951
return git_config_set_in_file_gently(given_config_source.file,
942-
argv[0], NULL);
952+
argv[0], NULL, NULL);
943953
}
944954
else if (actions == ACTION_UNSET_ALL) {
945955
check_write();
946956
check_argc(argc, 1, 2);
947957
return git_config_set_multivar_in_file_gently(given_config_source.file,
948958
argv[0], NULL, argv[1],
949-
flags | CONFIG_FLAGS_MULTI_REPLACE);
959+
NULL, flags | CONFIG_FLAGS_MULTI_REPLACE);
950960
}
951961
else if (actions == ACTION_RENAME_SECTION) {
952962
check_write();

builtin/gc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1553,7 +1553,7 @@ static int maintenance_register(int argc, const char **argv, const char *prefix)
15531553
die(_("$HOME not set"));
15541554
rc = git_config_set_multivar_in_file_gently(
15551555
config_file, "maintenance.repo", maintpath,
1556-
CONFIG_REGEX_NONE, 0);
1556+
CONFIG_REGEX_NONE, NULL, 0);
15571557
free(global_config_file);
15581558

15591559
if (rc)
@@ -1620,7 +1620,7 @@ static int maintenance_unregister(int argc, const char **argv, const char *prefi
16201620
if (!config_file)
16211621
die(_("$HOME not set"));
16221622
rc = git_config_set_multivar_in_file_gently(
1623-
config_file, key, NULL, maintpath,
1623+
config_file, key, NULL, maintpath, NULL,
16241624
CONFIG_FLAGS_MULTI_REPLACE | CONFIG_FLAGS_FIXED_VALUE);
16251625
free(global_config_file);
16261626

builtin/submodule--helper.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1283,7 +1283,7 @@ static void sync_submodule(const char *path, const char *prefix,
12831283
submodule_to_gitdir(&sb, path);
12841284
strbuf_addstr(&sb, "/config");
12851285

1286-
if (git_config_set_in_file_gently(sb.buf, remote_key, sub_origin_url))
1286+
if (git_config_set_in_file_gently(sb.buf, remote_key, NULL, sub_origin_url))
12871287
die(_("failed to update remote for submodule '%s'"),
12881288
path);
12891289

builtin/worktree.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,12 +365,12 @@ static void copy_filtered_worktree_config(const char *worktree_git_dir)
365365
if (!git_configset_get_bool(&cs, "core.bare", &bare) &&
366366
bare &&
367367
git_config_set_multivar_in_file_gently(
368-
to_file, "core.bare", NULL, "true", 0))
368+
to_file, "core.bare", NULL, "true", NULL, 0))
369369
error(_("failed to unset '%s' in '%s'"),
370370
"core.bare", to_file);
371371
if (!git_configset_get(&cs, "core.worktree") &&
372372
git_config_set_in_file_gently(to_file,
373-
"core.worktree", NULL))
373+
"core.worktree", NULL, NULL))
374374
error(_("failed to unset '%s' in '%s'"),
375375
"core.worktree", to_file);
376376

config.c

Lines changed: 72 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3006,6 +3006,7 @@ static ssize_t write_section(int fd, const char *key,
30063006
}
30073007

30083008
static ssize_t write_pair(int fd, const char *key, const char *value,
3009+
const char *comment,
30093010
const struct config_store_data *store)
30103011
{
30113012
int i;
@@ -3046,7 +3047,11 @@ static ssize_t write_pair(int fd, const char *key, const char *value,
30463047
strbuf_addch(&sb, value[i]);
30473048
break;
30483049
}
3049-
strbuf_addf(&sb, "%s\n", quote);
3050+
3051+
if (comment)
3052+
strbuf_addf(&sb, "%s%s\n", quote, comment);
3053+
else
3054+
strbuf_addf(&sb, "%s\n", quote);
30503055

30513056
ret = write_in_full(fd, sb.buf, sb.len);
30523057
strbuf_release(&sb);
@@ -3135,9 +3140,9 @@ static void maybe_remove_section(struct config_store_data *store,
31353140
}
31363141

31373142
int git_config_set_in_file_gently(const char *config_filename,
3138-
const char *key, const char *value)
3143+
const char *key, const char *comment, const char *value)
31393144
{
3140-
return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, 0);
3145+
return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, comment, 0);
31413146
}
31423147

31433148
void git_config_set_in_file(const char *config_filename,
@@ -3158,7 +3163,7 @@ int repo_config_set_worktree_gently(struct repository *r,
31583163
if (r->repository_format_worktree_config) {
31593164
char *file = repo_git_path(r, "config.worktree");
31603165
int ret = git_config_set_multivar_in_file_gently(
3161-
file, key, value, NULL, 0);
3166+
file, key, value, NULL, NULL, 0);
31623167
free(file);
31633168
return ret;
31643169
}
@@ -3172,6 +3177,62 @@ void git_config_set(const char *key, const char *value)
31723177
trace2_cmd_set_config(key, value);
31733178
}
31743179

3180+
/*
3181+
* The ownership rule is that the caller will own the string
3182+
* if it receives a piece of memory different from what it passed
3183+
* as the parameter.
3184+
*/
3185+
const char *git_config_prepare_comment_string(const char *comment)
3186+
{
3187+
size_t leading_blanks;
3188+
3189+
if (!comment)
3190+
return NULL;
3191+
3192+
if (strchr(comment, '\n'))
3193+
die(_("no multi-line comment allowed: '%s'"), comment);
3194+
3195+
/*
3196+
* If it begins with one or more leading whitespace characters
3197+
* followed by '#", the comment string is used as-is.
3198+
*
3199+
* If it begins with '#', a SP is inserted between the comment
3200+
* and the value the comment is about.
3201+
*
3202+
* Otherwise, the value is followed by a SP followed by '#'
3203+
* followed by SP and then the comment string comes.
3204+
*/
3205+
3206+
leading_blanks = strspn(comment, " \t");
3207+
if (leading_blanks && comment[leading_blanks] == '#')
3208+
; /* use it as-is */
3209+
else if (comment[0] == '#')
3210+
comment = xstrfmt(" %s", comment);
3211+
else
3212+
comment = xstrfmt(" # %s", comment);
3213+
3214+
return comment;
3215+
}
3216+
3217+
static void validate_comment_string(const char *comment)
3218+
{
3219+
size_t leading_blanks;
3220+
3221+
if (!comment)
3222+
return;
3223+
/*
3224+
* The front-end must have massaged the comment string
3225+
* properly before calling us.
3226+
*/
3227+
if (strchr(comment, '\n'))
3228+
BUG("multi-line comments are not permitted: '%s'", comment);
3229+
3230+
leading_blanks = strspn(comment, " \t");
3231+
if (!leading_blanks || comment[leading_blanks] != '#')
3232+
BUG("comment must begin with one or more SP followed by '#': '%s'",
3233+
comment);
3234+
}
3235+
31753236
/*
31763237
* If value==NULL, unset in (remove from) config,
31773238
* if value_pattern!=NULL, disregard key/value pairs where value does not match.
@@ -3200,6 +3261,7 @@ void git_config_set(const char *key, const char *value)
32003261
int git_config_set_multivar_in_file_gently(const char *config_filename,
32013262
const char *key, const char *value,
32023263
const char *value_pattern,
3264+
const char *comment,
32033265
unsigned flags)
32043266
{
32053267
int fd = -1, in_fd = -1;
@@ -3210,6 +3272,8 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
32103272
size_t contents_sz;
32113273
struct config_store_data store = CONFIG_STORE_INIT;
32123274

3275+
validate_comment_string(comment);
3276+
32133277
/* parse-key returns negative; flip the sign to feed exit(3) */
32143278
ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
32153279
if (ret)
@@ -3250,7 +3314,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
32503314
free(store.key);
32513315
store.key = xstrdup(key);
32523316
if (write_section(fd, key, &store) < 0 ||
3253-
write_pair(fd, key, value, &store) < 0)
3317+
write_pair(fd, key, value, comment, &store) < 0)
32543318
goto write_err_out;
32553319
} else {
32563320
struct stat st;
@@ -3404,7 +3468,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
34043468
if (write_section(fd, key, &store) < 0)
34053469
goto write_err_out;
34063470
}
3407-
if (write_pair(fd, key, value, &store) < 0)
3471+
if (write_pair(fd, key, value, comment, &store) < 0)
34083472
goto write_err_out;
34093473
}
34103474

@@ -3449,7 +3513,7 @@ void git_config_set_multivar_in_file(const char *config_filename,
34493513
const char *value_pattern, unsigned flags)
34503514
{
34513515
if (!git_config_set_multivar_in_file_gently(config_filename, key, value,
3452-
value_pattern, flags))
3516+
value_pattern, NULL, flags))
34533517
return;
34543518
if (value)
34553519
die(_("could not set '%s' to '%s'"), key, value);
@@ -3472,7 +3536,7 @@ int repo_config_set_multivar_gently(struct repository *r, const char *key,
34723536
int res = git_config_set_multivar_in_file_gently(file,
34733537
key, value,
34743538
value_pattern,
3475-
flags);
3539+
NULL, flags);
34763540
free(file);
34773541
return res;
34783542
}

config.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ int git_config_pathname(const char **, const char *, const char *);
290290

291291
int git_config_expiry_date(timestamp_t *, const char *, const char *);
292292
int git_config_color(char *, const char *, const char *);
293-
int git_config_set_in_file_gently(const char *, const char *, const char *);
293+
int git_config_set_in_file_gently(const char *, const char *, const char *, const char *);
294294

295295
/**
296296
* write config values to a specific config file, takes a key/value pair as
@@ -336,7 +336,9 @@ int git_config_parse_key(const char *, char **, size_t *);
336336
int git_config_set_multivar_gently(const char *, const char *, const char *, unsigned);
337337
void git_config_set_multivar(const char *, const char *, const char *, unsigned);
338338
int repo_config_set_multivar_gently(struct repository *, const char *, const char *, const char *, unsigned);
339-
int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, unsigned);
339+
int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, const char *, unsigned);
340+
341+
const char *git_config_prepare_comment_string(const char *);
340342

341343
/**
342344
* takes four parameters:

0 commit comments

Comments
 (0)