From 40e48ea40f5dfe0fbf786efc89d4cf297f4525e1 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 15 Nov 2013 15:36:37 +0000 Subject: remote: Introduce git_remote_delete() --- src/remote.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 114 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/remote.c b/src/remote.c index ea638e373..8bd52e7f2 100644 --- a/src/remote.c +++ b/src/remote.c @@ -1303,13 +1303,14 @@ static int rename_remote_config_section( if (git_buf_printf(&old_section_name, "remote.%s", old_name) < 0) goto cleanup; - if (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0) - goto cleanup; + if (new_name && + (git_buf_printf(&new_section_name, "remote.%s", new_name) < 0)) + goto cleanup; error = git_config_rename_section( repo, git_buf_cstr(&old_section_name), - git_buf_cstr(&new_section_name)); + new_name ? git_buf_cstr(&new_section_name) : NULL); cleanup: git_buf_free(&old_section_name); @@ -1747,3 +1748,113 @@ int git_remote_init_callbacks(git_remote_callbacks* opts, int version) return 0; } } + +struct branch_removal_data { + git_vector branches; + const char *name; +}; + +static int retrieve_branches_cb( + const git_config_entry *entry, + void *payload) +{ + int error; + struct branch_removal_data *data = (struct branch_removal_data *)payload; + + if (strcmp(data->name, entry->value)) + return 0; + + error = git_vector_insert( + &data->branches, + git__strndup( + entry->name + strlen("branch."), + strlen(entry->name) - strlen("branch.") - strlen(".remote"))); + + return error; +} + +static int delete_branch_remote_config_entry( + git_config *config, + const char *branch_name) +{ + int error; + + git_buf config_entry = GIT_BUF_INIT; + + if (git_buf_printf(&config_entry, "branch.%s.%s", branch_name, "remote") < 0) + return -1; + + if ((error = git_config_delete_entry(config, git_buf_cstr(&config_entry))) < 0) + goto cleanup; + + git_buf_clear(&config_entry); + + if (git_buf_printf(&config_entry, "branch.%s.%s", branch_name, "merge") < 0) + return -1; + + error = git_config_delete_entry(config, git_buf_cstr(&config_entry)); + +cleanup: + git_buf_free(&config_entry); + + return error; +} + +static int remove_branch_config_related_entries( + git_repository *repo, + const char *remote_name) +{ + int error; + git_config *config; + size_t i; + char *branch_name; + struct branch_removal_data data; + + if ((error = git_repository_config__weakptr(&config, repo)) < 0) + return error; + + if ((error = git_vector_init(&data.branches, 4, git__strcmp_cb)) < 0) + return error; + + data.name = remote_name; + + error = git_config_foreach_match( + config, "branch\\..+\\.remote", retrieve_branches_cb, &data); + + git_vector_foreach(&data.branches, i, branch_name) { + if (!error) + error = delete_branch_remote_config_entry(config, branch_name); + + git__free(branch_name); + } + + git_vector_free(&data.branches); + return error; +} + +int git_remote_delete(git_remote *remote) +{ + int error; + git_repository *repo; + + assert(remote); + + if (!remote->name) { + giterr_set(GITERR_INVALID, "Can't delete an anonymous remote."); + return -1; + } + + repo = git_remote_owner(remote); + + if ((error = rename_remote_config_section( + repo, git_remote_name(remote), NULL)) < 0) + return error; + + if ((error = remove_branch_config_related_entries(repo, + git_remote_name(remote))) < 0) + return error; + + git_remote_free(remote); + + return 0; +} -- cgit v1.2.1 From 5cdac19caa6c0bf81c5a71d3801be73281387cd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 30 Apr 2014 08:29:14 +0200 Subject: remote: move branch upstream deletion to use an iterator This should make it more readable and allocate a bunch fewer strings. --- src/remote.c | 95 ++++++++++++++++++++++++------------------------------------ 1 file changed, 38 insertions(+), 57 deletions(-) (limited to 'src') diff --git a/src/remote.c b/src/remote.c index 8bd52e7f2..ca1099a7f 100644 --- a/src/remote.c +++ b/src/remote.c @@ -1749,55 +1749,19 @@ int git_remote_init_callbacks(git_remote_callbacks* opts, int version) } } -struct branch_removal_data { - git_vector branches; - const char *name; -}; - -static int retrieve_branches_cb( - const git_config_entry *entry, - void *payload) +/* asserts a branch..remote format */ +static const char *name_offset(size_t *len_out, const char *name) { - int error; - struct branch_removal_data *data = (struct branch_removal_data *)payload; - - if (strcmp(data->name, entry->value)) - return 0; - - error = git_vector_insert( - &data->branches, - git__strndup( - entry->name + strlen("branch."), - strlen(entry->name) - strlen("branch.") - strlen(".remote"))); - - return error; -} - -static int delete_branch_remote_config_entry( - git_config *config, - const char *branch_name) -{ - int error; - - git_buf config_entry = GIT_BUF_INIT; - - if (git_buf_printf(&config_entry, "branch.%s.%s", branch_name, "remote") < 0) - return -1; - - if ((error = git_config_delete_entry(config, git_buf_cstr(&config_entry))) < 0) - goto cleanup; + size_t prefix_len; + const char *dot; - git_buf_clear(&config_entry); + prefix_len = strlen("remote."); + dot = strchr(name + prefix_len, '.'); - if (git_buf_printf(&config_entry, "branch.%s.%s", branch_name, "merge") < 0) - return -1; - - error = git_config_delete_entry(config, git_buf_cstr(&config_entry)); + assert(dot); -cleanup: - git_buf_free(&config_entry); - - return error; + *len_out = dot - name - prefix_len; + return name + prefix_len; } static int remove_branch_config_related_entries( @@ -1806,29 +1770,46 @@ static int remove_branch_config_related_entries( { int error; git_config *config; - size_t i; - char *branch_name; - struct branch_removal_data data; + git_config_entry *entry; + git_config_iterator *iter; + git_buf buf = GIT_BUF_INIT; if ((error = git_repository_config__weakptr(&config, repo)) < 0) return error; - if ((error = git_vector_init(&data.branches, 4, git__strcmp_cb)) < 0) + if ((error = git_config_iterator_glob_new(&iter, config, "branch\\..+\\.remote")) < 0) return error; - data.name = remote_name; + /* find any branches with us as upstream and remove that config */ + while ((error = git_config_next(&entry, iter)) == 0) { + const char *branch; + size_t branch_len; - error = git_config_foreach_match( - config, "branch\\..+\\.remote", retrieve_branches_cb, &data); + if (strcmp(remote_name, entry->value)) + continue; - git_vector_foreach(&data.branches, i, branch_name) { - if (!error) - error = delete_branch_remote_config_entry(config, branch_name); + branch = name_offset(&branch_len, entry->name); - git__free(branch_name); + git_buf_clear(&buf); + if (git_buf_printf(&buf, "branch.%.*s.merge", (int)branch_len, branch) < 0) + break; + + if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) + break; + + git_buf_clear(&buf); + if (git_buf_printf(&buf, "branch.%.*s.remote", (int)branch_len, branch) < 0) + break; + + if ((error = git_config_delete_entry(config, git_buf_cstr(&buf))) < 0) + break; } - git_vector_free(&data.branches); + if (error == GIT_ITEROVER) + error = 0; + + git_buf_free(&buf); + git_config_iterator_free(iter); return error; } -- cgit v1.2.1 From ec8a949a58864272860a4838c6b3d862beda7076 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Wed, 30 Apr 2014 09:20:03 +0200 Subject: remote: remove remote-tracking branches on delete When we delete a remote, we also need to go through its fetch refspecs and remove the references they create locally. --- src/remote.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/remote.c b/src/remote.c index ca1099a7f..f55375398 100644 --- a/src/remote.c +++ b/src/remote.c @@ -1813,6 +1813,53 @@ static int remove_branch_config_related_entries( return error; } +static int remove_refs(git_repository *repo, const char *glob) +{ + git_reference_iterator *iter; + const char *name; + int error; + + if ((error = git_reference_iterator_glob_new(&iter, repo, glob)) < 0) + return error; + + while ((error = git_reference_next_name(&name, iter)) == 0) { + if ((error = git_reference_remove(repo, name)) < 0) + break; + } + git_reference_iterator_free(iter); + + if (error == GIT_ITEROVER) + error = 0; + + return error; +} + +static int remove_remote_tracking(git_repository *repo, const char *remote_name) +{ + git_remote *remote; + int error; + size_t i, count; + + /* we want to use what's on the config, regardless of changes to the instance in memory */ + if ((error = git_remote_load(&remote, repo, remote_name)) < 0) + return error; + + count = git_remote_refspec_count(remote); + for (i = 0; i < count; i++) { + const git_refspec *refspec = git_remote_get_refspec(remote, i); + + /* shouldn't ever actually happen */ + if (refspec == NULL) + continue; + + if ((error = remove_refs(repo, git_refspec_dst(refspec))) < 0) + break; + } + + git_remote_free(remote); + return error; +} + int git_remote_delete(git_remote *remote) { int error; @@ -1827,14 +1874,17 @@ int git_remote_delete(git_remote *remote) repo = git_remote_owner(remote); - if ((error = rename_remote_config_section( - repo, git_remote_name(remote), NULL)) < 0) - return error; - if ((error = remove_branch_config_related_entries(repo, git_remote_name(remote))) < 0) return error; + if ((error = remove_remote_tracking(repo, git_remote_name(remote))) < 0) + return error; + + if ((error = rename_remote_config_section( + repo, git_remote_name(remote), NULL)) < 0) + return error; + git_remote_free(remote); return 0; -- cgit v1.2.1