Commit 129788a623816e06eb502235451beeb87472cee0

Patrick Steinhardt 2015-03-18T11:45:18

Implement git_submodule_set_branch.

diff --git a/include/git2/submodule.h b/include/git2/submodule.h
index 245b2a2..86f5fef 100644
--- a/include/git2/submodule.h
+++ b/include/git2/submodule.h
@@ -371,6 +371,22 @@ GIT_EXTERN(int) git_submodule_resolve_url(git_buf *out, git_repository *repo, co
 GIT_EXTERN(const char *) git_submodule_branch(git_submodule *submodule);
 
 /**
+ * Set the branch for the submodule.
+ *
+ * This sets the branch in memory for the submodule. This will be used for
+ * any following submodule actions while this submodule data is in memory.
+ *
+ * After calling this, you may wish to call `git_submodule_save()` to write
+ * the changes back to the ".gitmodules" file and `git_submodule_sync()` to
+ * write the changes to the checked out submodule repository.
+ *
+ * @param submodule Pointer to the submodule object
+ * @param branch Branch that should be used for the submodule
+ * @return 0 on success, <0 on failure
+ */
+GIT_EXTERN(int) git_submodule_set_branch(git_submodule *submodule, const char *branch);
+
+/**
  * Set the URL for the submodule.
  *
  * This sets the URL in memory for the submodule. This will be used for
diff --git a/src/submodule.c b/src/submodule.c
index c3bb6fe..d24a777 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -628,8 +628,17 @@ int git_submodule_save(git_submodule *submodule)
 		(error = git_config_file_set_string(mods, key.ptr, submodule->url)) < 0)
 		goto cleanup;
 
-	if ((error = submodule_config_key_trunc_puts(&key, "branch")) < 0 ||
-		(error = git_config_file_set_string(mods, key.ptr, submodule->branch)) < 0)
+	if ((error = submodule_config_key_trunc_puts(&key, "branch")) < 0)
+		goto cleanup;
+	if (submodule->branch == NULL)
+		error = git_config_file_delete(mods, key.ptr);
+	else
+		error = git_config_file_set_string(mods, key.ptr, submodule->branch);
+	if (error == GIT_ENOTFOUND) {
+		error = 0;
+		giterr_clear();
+	}
+	if (error < 0)
 		goto cleanup;
 
 	if (!(error = submodule_config_key_trunc_puts(&key, "update")) &&
@@ -715,6 +724,21 @@ const char *git_submodule_branch(git_submodule *submodule)
 	return submodule->branch;
 }
 
+int git_submodule_set_branch(git_submodule *submodule, const char *branch)
+{
+	assert(submodule);
+
+	git__free(submodule->branch);
+	submodule->branch = NULL;
+
+	if (branch != NULL) {
+		submodule->branch = git__strdup(branch);
+		GITERR_CHECK_ALLOC(submodule->branch);
+	}
+
+	return 0;
+}
+
 int git_submodule_set_url(git_submodule *submodule, const char *url)
 {
 	assert(submodule && url);
diff --git a/tests/submodule/modify.c b/tests/submodule/modify.c
index fcb4c22..1ede56e 100644
--- a/tests/submodule/modify.c
+++ b/tests/submodule/modify.c
@@ -6,8 +6,9 @@
 
 static git_repository *g_repo = NULL;
 
-#define SM_LIBGIT2_URL "https://github.com/libgit2/libgit2.git"
-#define SM_LIBGIT2     "sm_libgit2"
+#define SM_LIBGIT2_URL    "https://github.com/libgit2/libgit2.git"
+#define SM_LIBGIT2_BRANCH "github-branch"
+#define SM_LIBGIT2        "sm_libgit2"
 
 void test_submodule_modify__initialize(void)
 {
@@ -132,7 +133,7 @@ void test_submodule_modify__sync(void)
 void test_submodule_modify__edit_and_save(void)
 {
 	git_submodule *sm1, *sm2;
-	char *old_url;
+	char *old_url, *old_branch;
 	git_submodule_ignore_t old_ignore;
 	git_submodule_update_t old_update;
 	git_repository *r2;
@@ -141,15 +142,18 @@ void test_submodule_modify__edit_and_save(void)
 	cl_git_pass(git_submodule_lookup(&sm1, g_repo, "sm_changed_head"));
 
 	old_url = git__strdup(git_submodule_url(sm1));
+	old_branch = NULL;
 
 	/* modify properties of submodule */
 	cl_git_pass(git_submodule_set_url(sm1, SM_LIBGIT2_URL));
+	cl_git_pass(git_submodule_set_branch(sm1, SM_LIBGIT2_BRANCH));
 	old_ignore = git_submodule_set_ignore(sm1, GIT_SUBMODULE_IGNORE_UNTRACKED);
 	old_update = git_submodule_set_update(sm1, GIT_SUBMODULE_UPDATE_REBASE);
 	old_fetchrecurse = git_submodule_set_fetch_recurse_submodules(
 		sm1, GIT_SUBMODULE_RECURSE_YES);
 
 	cl_assert_equal_s(SM_LIBGIT2_URL, git_submodule_url(sm1));
+	cl_assert_equal_s(SM_LIBGIT2_BRANCH, git_submodule_branch(sm1));
 	cl_assert_equal_i(
 		GIT_SUBMODULE_IGNORE_UNTRACKED, git_submodule_ignore(sm1));
 	cl_assert_equal_i(
@@ -159,6 +163,7 @@ void test_submodule_modify__edit_and_save(void)
 
 	/* revert without saving (and confirm setters return old value) */
 	cl_git_pass(git_submodule_set_url(sm1, old_url));
+	cl_git_pass(git_submodule_set_branch(sm1, old_branch));
 	cl_assert_equal_i(
 		GIT_SUBMODULE_IGNORE_UNTRACKED,
 		git_submodule_set_ignore(sm1, GIT_SUBMODULE_IGNORE_RESET));
@@ -171,6 +176,7 @@ void test_submodule_modify__edit_and_save(void)
 
 	/* check that revert was successful */
 	cl_assert_equal_s(old_url, git_submodule_url(sm1));
+	cl_assert_equal_s(old_branch, git_submodule_branch(sm1));
 	cl_assert_equal_i((int)old_ignore, (int)git_submodule_ignore(sm1));
 	cl_assert_equal_i((int)old_update, (int)git_submodule_update_strategy(sm1));
 	cl_assert_equal_i(
@@ -178,6 +184,7 @@ void test_submodule_modify__edit_and_save(void)
 
 	/* modify properties of submodule (again) */
 	cl_git_pass(git_submodule_set_url(sm1, SM_LIBGIT2_URL));
+	cl_git_pass(git_submodule_set_branch(sm1, SM_LIBGIT2_BRANCH));
 	git_submodule_set_ignore(sm1, GIT_SUBMODULE_IGNORE_UNTRACKED);
 	git_submodule_set_update(sm1, GIT_SUBMODULE_UPDATE_REBASE);
 	git_submodule_set_fetch_recurse_submodules(sm1, GIT_SUBMODULE_RECURSE_YES);
@@ -202,12 +209,19 @@ void test_submodule_modify__edit_and_save(void)
 	cl_git_pass(git_submodule_reload(sm1, 0));
 
 	cl_assert_equal_s(SM_LIBGIT2_URL, git_submodule_url(sm1));
+	cl_assert_equal_s(SM_LIBGIT2_BRANCH, git_submodule_branch(sm1));
 	cl_assert_equal_i(
 		(int)GIT_SUBMODULE_IGNORE_UNTRACKED, (int)git_submodule_ignore(sm1));
 	cl_assert_equal_i(
 		(int)GIT_SUBMODULE_UPDATE_REBASE, (int)git_submodule_update_strategy(sm1));
 	cl_assert_equal_i(GIT_SUBMODULE_RECURSE_YES, git_submodule_fetch_recurse_submodules(sm1));
 
+	/* unset branch again and verify that the property is deleted in config */
+	cl_git_pass(git_submodule_set_branch(sm1, NULL));
+	cl_git_pass(git_submodule_save(sm1));
+	cl_git_pass(git_submodule_reload(sm1, 0));
+	cl_assert_equal_s(NULL, git_submodule_branch(sm1));
+
 	/* open a second copy of the repo and compare submodule */
 	cl_git_pass(git_repository_open(&r2, "submod2"));
 	cl_git_pass(git_submodule_lookup(&sm2, r2, "sm_changed_head"));
@@ -236,3 +250,11 @@ void test_submodule_modify__edit_and_save(void)
 	git_repository_free(r2);
 	git__free(old_url);
 }
+
+void test_submodule_modify__save_last(void)
+{
+	git_submodule *sm;
+
+	cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_gitmodules_only"));
+	cl_git_pass(git_submodule_save(sm));
+}