Commit 43b5075df4c543fc8801ed4b829702d7f9f2c0ad

Edward Thomson 2021-07-22T17:07:56

Merge pull request #5890 from lolgear/git_submodule_dup [Submodule] Git submodule dup

diff --git a/include/git2/submodule.h b/include/git2/submodule.h
index bedd76d..29d8bc1 100644
--- a/include/git2/submodule.h
+++ b/include/git2/submodule.h
@@ -224,6 +224,15 @@ GIT_EXTERN(int) git_submodule_lookup(
 	const char *name);
 
 /**
+ * Create an in-memory copy of a submodule. The copy must be explicitly
+ * free'd or it will leak.
+ *
+ * @param out Pointer to store the copy of the submodule.
+ * @param source Original submodule to copy.
+ */
+GIT_EXTERN(int) git_submodule_dup(git_submodule **out, git_submodule *source);
+
+/**
  * Release a submodule
  *
  * @param submodule Submodule object
diff --git a/src/submodule.c b/src/submodule.c
index 1486945..7cbb9fa 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -1854,6 +1854,17 @@ static void submodule_release(git_submodule *sm)
 	git__free(sm);
 }
 
+int git_submodule_dup(git_submodule **out, git_submodule *source)
+{
+	GIT_ASSERT_ARG(out);
+	GIT_ASSERT_ARG(source);
+
+	GIT_REFCOUNT_INC(source);
+
+	*out = source;
+	return 0;
+}
+
 void git_submodule_free(git_submodule *sm)
 {
 	if (!sm)
diff --git a/tests/submodule/lookup.c b/tests/submodule/lookup.c
index 6f7506d..f49ebb4 100644
--- a/tests/submodule/lookup.c
+++ b/tests/submodule/lookup.c
@@ -42,6 +42,46 @@ void test_submodule_lookup__simple_lookup(void)
 	assert_submodule_exists(g_repo, "sm_added_and_uncommited/");
 }
 
+void test_submodule_lookup__can_be_dupped(void)
+{
+	git_submodule *sm;
+	git_submodule *sm_duplicate;
+	const char *oid = "480095882d281ed676fe5b863569520e54a7d5c0";
+
+	/* Check original */
+	cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+	cl_assert(git_submodule_owner(sm) == g_repo);
+	cl_assert_equal_s("sm_unchanged", git_submodule_name(sm));
+	cl_assert(git__suffixcmp(git_submodule_path(sm), "sm_unchanged") == 0);
+	cl_assert(git__suffixcmp(git_submodule_url(sm), "/submod2_target") == 0);
+
+	cl_assert(git_oid_streq(git_submodule_index_id(sm), oid) == 0);
+	cl_assert(git_oid_streq(git_submodule_head_id(sm), oid) == 0);
+	cl_assert(git_oid_streq(git_submodule_wd_id(sm), oid) == 0);
+
+	cl_assert(git_submodule_ignore(sm) == GIT_SUBMODULE_IGNORE_NONE);
+	cl_assert(git_submodule_update_strategy(sm) == GIT_SUBMODULE_UPDATE_CHECKOUT);
+
+	/* Duplicate and free original */
+	cl_assert(git_submodule_dup(&sm_duplicate, sm) == 0);
+	git_submodule_free(sm);
+
+	/* Check duplicate */
+	cl_assert(git_submodule_owner(sm_duplicate) == g_repo);
+	cl_assert_equal_s("sm_unchanged", git_submodule_name(sm_duplicate));
+	cl_assert(git__suffixcmp(git_submodule_path(sm_duplicate), "sm_unchanged") == 0);
+	cl_assert(git__suffixcmp(git_submodule_url(sm_duplicate), "/submod2_target") == 0);
+
+	cl_assert(git_oid_streq(git_submodule_index_id(sm_duplicate), oid) == 0);
+	cl_assert(git_oid_streq(git_submodule_head_id(sm_duplicate), oid) == 0);
+	cl_assert(git_oid_streq(git_submodule_wd_id(sm_duplicate), oid) == 0);
+
+	cl_assert(git_submodule_ignore(sm_duplicate) == GIT_SUBMODULE_IGNORE_NONE);
+	cl_assert(git_submodule_update_strategy(sm_duplicate) == GIT_SUBMODULE_UPDATE_CHECKOUT);
+
+	git_submodule_free(sm_duplicate);
+}
+
 void test_submodule_lookup__accessors(void)
 {
 	git_submodule *sm;