Commit 908f24fd13085d06a99666a3b6b1c54f6d4392af

Arthur Schreiber 2016-04-22T10:34:17

Allow creating copies of `git_reference` objects.

diff --git a/include/git2/refs.h b/include/git2/refs.h
index db84ed0..dee28cb 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -462,6 +462,17 @@ GIT_EXTERN(int) git_reference_foreach_name(
 	void *payload);
 
 /**
+ * Create a copy of an existing reference.
+ *
+ * Call `git_reference_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_reference_dup(git_reference **dest, git_reference *source);
+
+/**
  * Free the given reference.
  *
  * @param ref git_reference
diff --git a/src/refs.c b/src/refs.c
index 26c8002..bff443a 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -105,6 +105,18 @@ git_reference *git_reference__set_name(
 	return rewrite;
 }
 
+int git_reference_dup(git_reference **dest, git_reference *source)
+{
+	if (source->type == GIT_REF_SYMBOLIC)
+		*dest = git_reference__alloc_symbolic(source->name, source->target.symbolic);
+	else
+		*dest = git_reference__alloc(source->name, &source->target.oid, &source->peel);
+
+	GITERR_CHECK_ALLOC(*dest);
+
+	return 0;
+}
+
 void git_reference_free(git_reference *reference)
 {
 	if (reference == NULL)
@@ -448,7 +460,7 @@ int git_reference_create_matching(
 {
 	int error;
 	git_signature *who = NULL;
-	
+
 	assert(id);
 
 	if ((error = git_reference__log_signature(&who, repo)) < 0)
diff --git a/tests/refs/dup.c b/tests/refs/dup.c
new file mode 100644
index 0000000..0fc635a
--- /dev/null
+++ b/tests/refs/dup.c
@@ -0,0 +1,40 @@
+#include "clar_libgit2.h"
+#include "refs.h"
+
+static git_repository *g_repo;
+
+void test_refs_dup__initialize(void)
+{
+	g_repo = cl_git_sandbox_init("testrepo.git");
+}
+
+void test_refs_dup__cleanup(void)
+{
+	cl_git_sandbox_cleanup();
+}
+
+void test_refs_dup__direct(void)
+{
+	git_reference *a, *b;
+
+	cl_git_pass(git_reference_lookup(&a, g_repo, "refs/heads/master"));
+	cl_git_pass(git_reference_dup(&b, a));
+
+	cl_assert(git_reference_cmp(a, b) == 0);
+
+	git_reference_free(b);
+	git_reference_free(a);
+}
+
+void test_refs_dup__symbolic(void)
+{
+	git_reference *a, *b;
+
+	cl_git_pass(git_reference_lookup(&a, g_repo, "HEAD"));
+	cl_git_pass(git_reference_dup(&b, a));
+
+	cl_assert(git_reference_cmp(a, b) == 0);
+
+	git_reference_free(b);
+	git_reference_free(a);
+}