diff --git a/include/git2/remote.h b/include/git2/remote.h index 82aff385d..153bd1e42 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -43,10 +43,10 @@ typedef int (*git_remote_rename_problem_cb)(const char *problematic_refspec, voi * See `git_tag_create()` for rules about valid names. * * @param out pointer to the new remote object - * @param repo the associated repository - * @param name the optional remote's name + * @param repo the associated repository. May be NULL for a "dangling" remote. + * @param name the optional remote's name. May be NULL. * @param url the remote repository's URL - * @param fetch the fetch refspec to use for this remote + * @param fetch the fetch refspec to use for this remote. May be NULL for defaults. * @return 0, GIT_EINVALIDSPEC or an error code */ GIT_EXTERN(int) git_remote_new(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch); diff --git a/src/remote.c b/src/remote.c index 670904b17..3101ff7ba 100644 --- a/src/remote.c +++ b/src/remote.c @@ -88,7 +88,7 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *name, con git_remote *remote; /* name is optional */ - assert(out && repo && url); + assert(out && url); remote = git__calloc(1, sizeof(git_remote)); GITERR_CHECK_ALLOC(remote); @@ -289,6 +289,11 @@ int git_remote_save(const git_remote *remote) assert(remote); + if (!remote->repo) { + giterr_set(GITERR_INVALID, "Can't save a dangling remote."); + return GIT_ERROR; + } + if ((error = ensure_remote_name_is_valid(remote->name)) < 0) return error; @@ -543,7 +548,7 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur assert(remote); - if (!proxy_url) + if (!proxy_url || !remote->repo) return -1; *proxy_url = NULL; @@ -745,6 +750,11 @@ int git_remote_update_tips(git_remote *remote) assert(remote); + if (!remote->repo) { + giterr_set(GITERR_INVALID, "Can't update tips on a dangling remote."); + return GIT_ERROR; + } + spec = &remote->fetch; if (git_repository_odb__weakptr(&odb, remote->repo) < 0) @@ -1293,50 +1303,52 @@ int git_remote_rename( assert(remote && new_name); - if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0) - return error; - if ((error = ensure_remote_name_is_valid(new_name)) < 0) return error; - if (!remote->name) { + if (remote->repo) { + if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0) + return error; + + if (!remote->name) { + if ((error = rename_fetch_refspecs( + remote, + new_name, + callback, + payload)) < 0) + return error; + + remote->name = git__strdup(new_name); + + return git_remote_save(remote); + } + + if ((error = rename_remote_config_section( + remote->repo, + remote->name, + new_name)) < 0) + return error; + + if ((error = update_branch_remote_config_entry( + remote->repo, + remote->name, + new_name)) < 0) + return error; + + if ((error = rename_remote_references( + remote->repo, + remote->name, + new_name)) < 0) + return error; + if ((error = rename_fetch_refspecs( remote, new_name, callback, payload)) < 0) return error; - - remote->name = git__strdup(new_name); - - return git_remote_save(remote); } - if ((error = rename_remote_config_section( - remote->repo, - remote->name, - new_name)) < 0) - return error; - - if ((error = update_branch_remote_config_entry( - remote->repo, - remote->name, - new_name)) < 0) - return error; - - if ((error = rename_remote_references( - remote->repo, - remote->name, - new_name)) < 0) - return error; - - if ((error = rename_fetch_refspecs( - remote, - new_name, - callback, - payload)) < 0) - return error; - git__free(remote->name); remote->name = git__strdup(new_name); diff --git a/tests-clar/network/remotes.c b/tests-clar/network/remotes.c index 70df001e7..d3f9ff80f 100644 --- a/tests-clar/network/remotes.c +++ b/tests-clar/network/remotes.c @@ -326,3 +326,13 @@ void test_network_remotes__check_structure_version(void) err = giterr_last(); cl_assert_equal_i(GITERR_INVALID, err->klass); } + +void test_network_remotes__dangling(void) +{ + cl_git_pass(git_remote_new(&_remote, NULL, "upstream", "git://github.com/libgit2/libgit2", NULL)); + cl_git_fail(git_remote_save(_remote)); + cl_git_fail(git_remote_update_tips(_remote)); + + cl_git_pass(git_remote_rename(_remote, "newname", NULL, NULL)); + cl_assert_equal_s(git_remote_name(_remote), "newname"); +}