Commit 40ef47dd46fdd361b49ccc97605a93e0993e96db

Arthur Schreiber 2014-01-14T21:03:01

Add `git_remote_dup`.

diff --git a/include/git2/remote.h b/include/git2/remote.h
index 7410909..d3e6caa 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -108,6 +108,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
  *
  * @param remote the remote
diff --git a/src/remote.c b/src/remote.c
index 294a870..6a4a707 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 954ded8..235a102 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;