diff --git a/include/git2/remote.h b/include/git2/remote.h index 7410909dc..d3e6caa48 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -107,6 +107,18 @@ GIT_EXTERN(int) git_remote_load(git_remote **out, git_repository *repo, const ch */ GIT_EXTERN(int) git_remote_save(const git_remote *remote); +/** + * Create a copy of an existing remote. All internal strings are also + * duplicated. Callbacks are not duplicated. + * + * Call `git_remote_free` to free the data. + * + * @param dest pointer where to store the copy + * @param source object to copy + * @return 0 or an error code + */ +GIT_EXTERN(int) git_remote_dup(git_remote **dest, const git_remote *source); + /** * Get the remote's repository * diff --git a/src/remote.c b/src/remote.c index 294a8709d..6a4a707a4 100644 --- a/src/remote.c +++ b/src/remote.c @@ -248,6 +248,47 @@ int git_remote_create_inmemory(git_remote **out, git_repository *repo, const cha return 0; } +int git_remote_dup(git_remote **dest, const git_remote *source) +{ + int error; + git_remote *remote = git__calloc(1, sizeof(git_remote)); + GITERR_CHECK_ALLOC(remote); + + memset(remote, 0x0, sizeof(git_remote)); + + if (source->name != NULL) { + remote->name = git__strdup(source->name); + GITERR_CHECK_ALLOC(remote->name); + } + + if (source->url != NULL) { + remote->url = git__strdup(source->url); + GITERR_CHECK_ALLOC(remote->url); + } + + if (source->pushurl != NULL) { + remote->pushurl = git__strdup(source->pushurl); + GITERR_CHECK_ALLOC(remote->pushurl); + } + + remote->repo = source->repo; + remote->need_pack = source->need_pack; + remote->download_tags = source->download_tags; + remote->check_cert = source->check_cert; + remote->update_fetchhead = source->update_fetchhead; + + if ((error = git_vector_dup(&remote->refs, &source->refs, NULL)) < 0 || + (error = git_vector_dup(&remote->refspecs, &source->refspecs, NULL)) < 0 || + (error = git_vector_dup(&remote->active_refspecs, &source->active_refspecs, NULL))) { + git__free(remote); + return error; + } + + *dest = remote; + + return 0; +} + struct refspec_cb_data { git_remote *remote; int fetch; diff --git a/tests/network/remote/remotes.c b/tests/network/remote/remotes.c index 954ded82c..235a1022d 100644 --- a/tests/network/remote/remotes.c +++ b/tests/network/remote/remotes.c @@ -129,6 +129,27 @@ void test_network_remote_remotes__add_fetchspec(void) cl_assert_equal_b(_refspec->push, false); } +void test_network_remote_remotes__dup(void) +{ + git_strarray array; + git_remote *dup; + + cl_git_pass(git_remote_dup(&dup, _remote)); + + cl_assert_equal_s(git_remote_name(dup), git_remote_name(_remote)); + cl_assert_equal_s(git_remote_url(dup), git_remote_url(_remote)); + cl_assert_equal_s(git_remote_pushurl(dup), git_remote_pushurl(_remote)); + + cl_git_pass(git_remote_get_fetch_refspecs(&array, _remote)); + cl_assert_equal_i(1, (int)array.count); + cl_assert_equal_s("+refs/heads/*:refs/remotes/test/*", array.strings[0]); + git_strarray_free(&array); + + cl_git_pass(git_remote_get_push_refspecs(&array, _remote)); + cl_assert_equal_i(0, (int)array.count); + git_strarray_free(&array); +} + void test_network_remote_remotes__add_pushspec(void) { size_t size;