branch: rename config section upon moving
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
diff --git a/src/branch.c b/src/branch.c
index a1c2abc..9562805 100644
--- a/src/branch.c
+++ b/src/branch.c
@@ -89,30 +89,59 @@ cleanup:
return error;
}
-static int delete_config_entries_cb(
+typedef struct rename_data
+{
+ git_config *config;
+ const char *old_name;
+ const char *new_name;
+} rename_data;
+
+static int rename_config_entries_cb(
const char *var_name,
const char *value,
void *payload)
{
- git_config *config;
+ rename_data *data = (rename_data *)payload;
GIT_UNUSED(value);
- config = (git_config *)payload;
+ if (data->new_name != NULL) {
+ git_buf name = GIT_BUF_INIT;
+ int error;
+
+ if (git_buf_printf(
+ &name,
+ "branch.%s.%s",
+ data->new_name,
+ var_name + strlen("branch") + strlen(data->old_name) + 2) < 0)
+ return -1;
+
+ error = git_config_set_string(
+ data->config,
+ git_buf_cstr(&name),
+ value);
+
+ git_buf_free(&name);
+
+ if (error)
+ return error;
+ }
- return git_config_delete(config, var_name);
+ return git_config_delete(data->config, var_name);
}
-static int delete_branch_config_entries(
+static int rename_branch_config_entries(
git_repository *repo,
- const char *branch_name)
+ const char *old_branch_name,
+ const char *new_branch_name)
{
git_config *config;
git_buf pattern = GIT_BUF_INIT;
int error = -1;
+ rename_data data;
git_buf_sets(&pattern, "branch\\.");
- git_buf_puts_escape_regex(&pattern, branch_name);
+ git_buf_puts_escape_regex(&pattern, old_branch_name);
git_buf_puts(&pattern, "\\..+");
if (git_buf_oom(&pattern))
goto cleanup;
@@ -120,10 +149,14 @@ static int delete_branch_config_entries(
if (git_repository_config__weakptr(&config, repo) < 0)
goto cleanup;
+ data.config = config;
+ data.old_name = old_branch_name;
+ data.new_name = new_branch_name;
+
if ((error = git_config_foreach_match(
config,
git_buf_cstr(&pattern),
- delete_config_entries_cb, config)) < 0)
+ rename_config_entries_cb, &data)) < 0)
goto cleanup;
error = 0;
@@ -154,9 +187,10 @@ int git_branch_delete(git_reference *branch)
return -1;
}
- if (delete_branch_config_entries(
+ if (rename_branch_config_entries(
git_reference_owner(branch),
- git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR)) < 0)
+ git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR),
+ NULL) < 0)
goto on_error;
return git_reference_delete(branch);
@@ -210,7 +244,8 @@ int git_branch_move(
const char *new_branch_name,
int force)
{
- git_buf new_reference_name = GIT_BUF_INIT;
+ git_buf new_reference_name = GIT_BUF_INIT,
+ old_branch_name = GIT_BUF_INIT;
int error;
assert(branch && new_branch_name);
@@ -221,10 +256,21 @@ int git_branch_move(
if ((error = git_buf_joinpath(&new_reference_name, GIT_REFS_HEADS_DIR, new_branch_name)) < 0)
goto cleanup;
- error = git_reference_rename(branch, git_buf_cstr(&new_reference_name), force);
+ if ((error = git_buf_puts(&old_branch_name, git_reference_name(branch) + strlen(GIT_REFS_HEADS_DIR))) < 0)
+ goto cleanup;
+
+ if ((error = git_reference_rename(branch, git_buf_cstr(&new_reference_name), force)) < 0)
+ goto cleanup;
+
+ if ((error = rename_branch_config_entries(
+ git_reference_owner(branch),
+ git_buf_cstr(&old_branch_name),
+ new_branch_name)) < 0)
+ goto cleanup;
cleanup:
git_buf_free(&new_reference_name);
+ git_buf_free(&old_branch_name);
return error;
}
diff --git a/tests-clar/refs/branches/move.c b/tests-clar/refs/branches/move.c
index 62b6042..0424690 100644
--- a/tests-clar/refs/branches/move.c
+++ b/tests-clar/refs/branches/move.c
@@ -1,5 +1,6 @@
#include "clar_libgit2.h"
#include "refs.h"
+#include "config/config_helpers.h"
static git_repository *repo;
static git_reference *ref;
@@ -63,6 +64,27 @@ void test_refs_branches_move__can_force_move_over_an_existing_branch(void)
cl_git_pass(git_branch_move(ref, "master", 1));
}
+void test_refs_branches_move__moving_a_branch_moves_related_configuration_data(void)
+{
+ git_reference *branch;
+
+ cl_git_pass(git_branch_lookup(&branch, repo, "track-local", GIT_BRANCH_LOCAL));
+
+ assert_config_entry_existence(repo, "branch.track-local.remote", true);
+ assert_config_entry_existence(repo, "branch.track-local.merge", true);
+ assert_config_entry_existence(repo, "branch.moved.remote", false);
+ assert_config_entry_existence(repo, "branch.moved.merge", false);
+
+ cl_git_pass(git_branch_move(branch, "moved", 0));
+
+ assert_config_entry_existence(repo, "branch.track-local.remote", false);
+ assert_config_entry_existence(repo, "branch.track-local.merge", false);
+ assert_config_entry_existence(repo, "branch.moved.remote", true);
+ assert_config_entry_existence(repo, "branch.moved.merge", true);
+
+ git_reference_free(branch);
+}
+
void test_refs_branches_move__moving_the_branch_pointed_at_by_HEAD_updates_HEAD(void)
{
git_reference *branch;