config: add --comment option to add a comment

Introduce the ability to append comments to modifications
made using git-config. Example usage:

  git config --comment "changed via script" \
    --add safe.directory /home/alice/repo.git

based on the proposed patch, the output produced is:

  [safe]
    directory = /home/alice/repo.git #changed via script

Users need to be able to distinguish between config entries made
using automation and entries made by a human. Automation can add
comments containing a URL pointing to explanations for the change
made, avoiding questions from users as to why their config file
was changed by a third party.

The implementation ensures that a # character is unconditionally
prepended to the provided comment string, and that the comment
text is appended as a suffix to the changed key-value-pair in the
same line of text. Multi-line comments (i.e. comments containing
linefeed) are rejected as errors, causing Git to exit without
making changes.

Comments are aimed at humans who inspect or change their Git
config using a pager or editor. Comments are not meant to be
read or displayed by git-config at a later time.

Signed-off-by: Ralph Seichter <github@seichter.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Ralph Seichter
2024-03-12 21:47:00 +00:00
committed by Junio C Hamano
parent 4f9b731bde
commit 42d5c03394
12 changed files with 78 additions and 45 deletions

View File

@ -3001,6 +3001,7 @@ static ssize_t write_section(int fd, const char *key,
}
static ssize_t write_pair(int fd, const char *key, const char *value,
const char *comment,
const struct config_store_data *store)
{
int i;
@ -3041,7 +3042,14 @@ static ssize_t write_pair(int fd, const char *key, const char *value,
strbuf_addch(&sb, value[i]);
break;
}
strbuf_addf(&sb, "%s\n", quote);
if (comment) {
if (strchr(comment, '\n'))
die(_("multi-line comments are not permitted: '%s'"), comment);
else
strbuf_addf(&sb, "%s #%s\n", quote, comment);
} else
strbuf_addf(&sb, "%s\n", quote);
ret = write_in_full(fd, sb.buf, sb.len);
strbuf_release(&sb);
@ -3130,9 +3138,9 @@ static void maybe_remove_section(struct config_store_data *store,
}
int git_config_set_in_file_gently(const char *config_filename,
const char *key, const char *value)
const char *key, const char *comment, const char *value)
{
return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, 0);
return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, comment, 0);
}
void git_config_set_in_file(const char *config_filename,
@ -3153,7 +3161,7 @@ int repo_config_set_worktree_gently(struct repository *r,
if (r->repository_format_worktree_config) {
char *file = repo_git_path(r, "config.worktree");
int ret = git_config_set_multivar_in_file_gently(
file, key, value, NULL, 0);
file, key, value, NULL, NULL, 0);
free(file);
return ret;
}
@ -3195,6 +3203,7 @@ void git_config_set(const char *key, const char *value)
int git_config_set_multivar_in_file_gently(const char *config_filename,
const char *key, const char *value,
const char *value_pattern,
const char *comment,
unsigned flags)
{
int fd = -1, in_fd = -1;
@ -3245,7 +3254,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
free(store.key);
store.key = xstrdup(key);
if (write_section(fd, key, &store) < 0 ||
write_pair(fd, key, value, &store) < 0)
write_pair(fd, key, value, comment, &store) < 0)
goto write_err_out;
} else {
struct stat st;
@ -3399,7 +3408,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
if (write_section(fd, key, &store) < 0)
goto write_err_out;
}
if (write_pair(fd, key, value, &store) < 0)
if (write_pair(fd, key, value, comment, &store) < 0)
goto write_err_out;
}
@ -3444,7 +3453,7 @@ void git_config_set_multivar_in_file(const char *config_filename,
const char *value_pattern, unsigned flags)
{
if (!git_config_set_multivar_in_file_gently(config_filename, key, value,
value_pattern, flags))
value_pattern, NULL, flags))
return;
if (value)
die(_("could not set '%s' to '%s'"), key, value);
@ -3467,7 +3476,7 @@ int repo_config_set_multivar_gently(struct repository *r, const char *key,
int res = git_config_set_multivar_in_file_gently(file,
key, value,
value_pattern,
flags);
NULL, flags);
free(file);
return res;
}