* git-config: document --rename-section, provide --remove-section This patch documents the previously undocumented option --rename-section and adds a new option to zap an entire section. diff --git a/Documentation/git-config.txt b/Documentation/git-config.txt index 6624484..68de588 100644 --- a/Documentation/git-config.txt +++ b/Documentation/git-config.txt @@ -16,6 +16,8 @@ SYNOPSIS 'git-config' [--global] [type] --get-all name [value_regex] 'git-config' [--global] [type] --unset name [value_regex] 'git-config' [--global] [type] --unset-all name [value_regex] +'git-config' [--global] [type] --rename-section old_name new_name +'git-config' [--global] [type] --remove-section name 'git-config' [--global] -l | --list DESCRIPTION @@ -74,6 +76,12 @@ OPTIONS --global:: Use global ~/.gitconfig file rather than the repository .git/config. +--remove-section:: + Remove the given section from the configuration file. + +--rename-section:: + Rename the given section to a new name. + --unset:: Remove the line matching the key from config file. diff --git a/builtin-config.c b/builtin-config.c index f1433a4..6b12fa1 100644 --- a/builtin-config.c +++ b/builtin-config.c @@ -2,7 +2,7 @@ #include "cache.h" static const char git_config_set_usage[] = -"git-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --list"; +"git-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --rename-section old_name new_name | --remove-section name | --list"; static char *key; static regex_t *key_regexp; @@ -168,6 +168,19 @@ int cmd_config(int argc, const char **argv, const char *prefix) } return 0; } + else if (!strcmp(argv[1], "--remove-section")) { + int ret; + if (argc != 3) + usage(git_config_set_usage); + ret = git_config_remove_section(argv[2]); + if (ret < 0) + return ret; + if (ret == 0) { + fprintf(stderr, "No such section!\n"); + return 1; + } + return 0; + } else break; argc--; diff --git a/config.c b/config.c index 0ff413b..49df7bd 100644 --- a/config.c +++ b/config.c @@ -854,6 +859,33 @@ write_err_out: } +static int section_name_match (const char *buf, const char *name) +{ + int i = 0, j = 0, dot = 0; + for (; buf[i] && buf[i] != ']'; i++) { + if (!dot && isspace(buf[i])) { + dot = 1; + if (name[j++] != '.') + break; + for (i++; isspace(buf[i]); i++) + ; /* do nothing */ + if (buf[i] != '"') + break; + continue; + } + if (buf[i] == '\\' && dot) + i++; + else if (buf[i] == '"' && dot) { + for (i++; isspace(buf[i]); i++) + ; /* do_nothing */ + break; + } + if (buf[i] != name[j++]) + break; + } + return (buf[i] == ']' && name[j] == 0); +} + int git_config_rename_section(const char *old_name, const char *new_name) { int ret = 0; @@ -885,40 +917,15 @@ int git_config_rename_section(const char *old_name, const char *new_name) int length; for (i = 0; buf[i] && isspace(buf[i]); i++) ; /* do nothing */ - if (buf[i] == '[') { + if (buf[i] == '[' && section_name_match (&buf[i+1], old_name)) { /* it's a section */ - int j = 0, dot = 0; - for (i++; buf[i] && buf[i] != ']'; i++) { - if (!dot && isspace(buf[i])) { - dot = 1; - if (old_name[j++] != '.') - break; - for (i++; isspace(buf[i]); i++) - ; /* do nothing */ - if (buf[i] != '"') - break; - continue; - } - if (buf[i] == '\\' && dot) - i++; - else if (buf[i] == '"' && dot) { - for (i++; isspace(buf[i]); i++) - ; /* do_nothing */ - break; - } - if (buf[i] != old_name[j++]) - break; - } - if (buf[i] == ']' && old_name[j] == 0) { - /* old_name matches */ - ret++; - store.baselen = strlen(new_name); - if (!store_write_section(out_fd, new_name)) { - ret = write_error(); - goto out; - } - continue; + ret++; + store.baselen = strlen(new_name); + if (!store_write_section(out_fd, new_name)) { + ret = write_error(); + goto out; } + continue; } length = strlen(buf); if (write_in_full(out_fd, buf, length) != length) { @@ -934,3 +941,58 @@ int git_config_rename_section(const char *old_name, const char *new_name) return ret; } +int git_config_remove_section(const char *name) +{ + int ret = 0; + char *config_filename; + struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1); + int out_fd; + int removing = 0; + char buf[1024]; + + config_filename = getenv(CONFIG_ENVIRONMENT); + if (!config_filename) { + config_filename = getenv(CONFIG_LOCAL_ENVIRONMENT); + if (!config_filename) + config_filename = git_path("config"); + } + config_filename = xstrdup(config_filename); + out_fd = hold_lock_file_for_update(lock, config_filename, 0); + if (out_fd < 0) { + ret = error("Could not lock config file!"); + goto out; + } + + if (!(config_file = fopen(config_filename, "rb"))) { + ret = error("Could not open config file!"); + goto out; + } + + while (fgets(buf, sizeof(buf), config_file)) { + int i; + int length; + for (i = 0; buf[i] && isspace(buf[i]); i++) + ; /* do nothing */ + if (buf[i] == '[') { + if (section_name_match (&buf[i + 1], name)) { + /* name matches */ + ret++; + removing = 1; + } else + removing = 0; + } + if (removing) + continue; + length = strlen(buf); + if (write_in_full(out_fd, buf, length) != length) { + ret = write_error(); + goto out; + } + } + fclose(config_file); + if (close(out_fd) || commit_lock_file(lock) < 0) + ret = error("Cannot commit config file!"); + out: + free(config_filename); + return ret; +} diff --git a/cache.h b/cache.h index 8bbc142..585a9b4 100644 --- a/cache.h +++ b/cache.h @@ -438,6 +439,7 @@ extern int git_config_bool(const char *, const char *); extern int git_config_set(const char *, const char *); extern int git_config_set_multivar(const char *, const char *, const char *, int); extern int git_config_rename_section(const char *, const char *); +extern int git_config_remove_section(const char *); extern int check_repository_format_version(const char *var, const char *value); #define MAX_GITNAME (1000)