diff --git a/builtin-repo-config.c b/builtin-repo-config.c index 64fbdb7b2420203cf1d142e73c5ec579c95cf581..a38099a63d20d6f4a8187770c84e3a180ebeaa52 100644 --- a/builtin-repo-config.c +++ b/builtin-repo-config.c @@ -3,7 +3,7 @@ #include static const char git_config_set_usage[] = -"git-repo-config [ --global ] [ --bool | --int ] [--get | --get-all | --get-regexp | --replace-all | --add | --unset | --unset-all] name [value [value_regex]] | --list"; +"git-repo-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"; static char *key; static regex_t *key_regexp; @@ -148,6 +148,18 @@ int cmd_repo_config(int argc, const char **argv, const char *prefix) } else { die("$HOME not set"); } + } else if (!strcmp(argv[1], "--rename-section")) { + int ret; + if (argc != 4) + usage(git_config_set_usage); + ret = git_config_rename_section(argv[2], argv[3]); + if (ret < 0) + return ret; + if (ret == 0) { + fprintf(stderr, "No such section!\n"); + return 1; + } + return 0; } else break; argc--; diff --git a/cache.h b/cache.h index b540292d669165cf144f3848e54f7494c1d37ad4..8ad5920d2be9593ad7810e3ccefa1c8b9f4e0750 100644 --- a/cache.h +++ b/cache.h @@ -405,6 +405,7 @@ extern int git_config_int(const char *, const char *); 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 check_repository_format_version(const char *var, const char *value); #define MAX_GITNAME (1000) diff --git a/config.c b/config.c index 1bdef44a3ad315ecc4cdfa879e9c0881bd82722b..663993fefa9d8c347d2ff4c1b40edbf3b0d19c90 100644 --- a/config.c +++ b/config.c @@ -746,4 +746,68 @@ int git_config_set_multivar(const char* key, const char* value, return ret; } +int git_config_rename_section(const char *old_name, const char *new_name) +{ + int ret = 0; + const char *config_filename; + struct lock_file *lock = xcalloc(sizeof(struct lock_file), 1); + int out_fd; + char buf[1024]; + + config_filename = getenv("GIT_CONFIG"); + if (!config_filename) { + config_filename = getenv("GIT_CONFIG_LOCAL"); + 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) + return error("Could not lock config file!"); + + if (!(config_file = fopen(config_filename, "rb"))) + return error("Could not open config file!"); + + while (fgets(buf, sizeof(buf), config_file)) { + int i; + for (i = 0; buf[i] && isspace(buf[i]); i++) + ; /* do nothing */ + if (buf[i] == '[') { + /* 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 matches */ + ret++; + store.baselen = strlen(new_name); + store_write_section(out_fd, new_name); + continue; + } + } + write(out_fd, buf, strlen(buf)); + } + if (close(out_fd) || commit_lock_file(lock) < 0) + return error("Cannot commit config file!"); + return ret; +} diff --git a/refs.c b/refs.c index a02957c399ded94bb9a49c9dc3d8ab5d9411bbec..d911b9e86009aa3d81c6c4d310a26bf057920e8a 100644 --- a/refs.c +++ b/refs.c @@ -867,6 +867,16 @@ int rename_ref(const char *oldref, const char *newref, const char *logmsg) goto rollback; } + if (!strncmp(oldref, "refs/heads/", 11) && + !strncmp(newref, "refs/heads/", 11)) { + char oldsection[1024], newsection[1024]; + + snprintf(oldsection, 1024, "branch.%s", oldref + 11); + snprintf(newsection, 1024, "branch.%s", newref + 11); + if (git_config_rename_section(oldsection, newsection) < 0) + return 1; + } + return 0; rollback: diff --git a/t/t1300-repo-config.sh b/t/t1300-repo-config.sh index 16cd6426100c0a58de854d3252a654c7ae28232a..e48a4ecdcf7129da1431928bdb942eae8c3e6515 100755 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@ -343,5 +343,53 @@ EOF test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect' +cat > .git/config << EOF +# Hallo + #Bello +[branch "eins"] + x = 1 +[branch.eins] + y = 1 + [branch "1 234 blabl/a"] +weird +EOF + +test_expect_success "rename section" \ + "git-repo-config --rename-section branch.eins branch.zwei" + +cat > expect << EOF +# Hallo + #Bello +[branch "zwei"] + x = 1 +[branch "zwei"] + y = 1 + [branch "1 234 blabl/a"] +weird +EOF + +test_expect_success "rename succeeded" "diff -u expect .git/config" + +test_expect_failure "rename non-existing section" \ + 'git-repo-config --rename-section branch."world domination" branch.drei' + +test_expect_success "rename succeeded" "diff -u expect .git/config" + +test_expect_success "rename another section" \ + 'git-repo-config --rename-section branch."1 234 blabl/a" branch.drei' + +cat > expect << EOF +# Hallo + #Bello +[branch "zwei"] + x = 1 +[branch "zwei"] + y = 1 +[branch "drei"] +weird +EOF + +test_expect_success "rename succeeded" "diff -u expect .git/config" + test_done diff --git a/t/t3200-branch.sh b/t/t3200-branch.sh index 5782c30b03a7e7bb7d244d305e13e856eed40a89..a6ea0f6a196c5285c229021c96bb83f33a3aa748 100755 --- a/t/t3200-branch.sh +++ b/t/t3200-branch.sh @@ -94,6 +94,8 @@ test_expect_failure \ git-branch r && git-branch -m q r/q' +git-repo-config branch.s/s.dummy Hello + test_expect_success \ 'git branch -m s/s s should work when s/t is deleted' \ 'git-branch -l s/s && @@ -104,6 +106,10 @@ test_expect_success \ git-branch -m s/s s && test -f .git/logs/refs/heads/s' +test_expect_success 'config information was renamed, too' \ + "test $(git-repo-config branch.s.dummy) = Hello && + ! git-repo-config branch.s/s/dummy" + test_expect_failure \ 'git-branch -m u v should fail when the reflog for u is a symlink' \ 'git-branch -l u &&