Commit a71c27ccda7f7118ac2c50789fc1407d4d940b98

Ben Straub 2012-12-12T12:15:25

Allow creation of dangling remotes

diff --git a/include/git2/remote.h b/include/git2/remote.h
index 82aff38..153bd1e 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -43,10 +43,10 @@ typedef int (*git_remote_rename_problem_cb)(const char *problematic_refspec, voi
  * See `git_tag_create()` for rules about valid names.
  *
  * @param out pointer to the new remote object
- * @param repo the associated repository
- * @param name the optional remote's name
+ * @param repo the associated repository. May be NULL for a "dangling" remote.
+ * @param name the optional remote's name. May be NULL.
  * @param url the remote repository's URL
- * @param fetch the fetch refspec to use for this remote
+ * @param fetch the fetch refspec to use for this remote. May be NULL for defaults.
  * @return 0, GIT_EINVALIDSPEC or an error code
  */
 GIT_EXTERN(int) git_remote_new(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch);
diff --git a/src/remote.c b/src/remote.c
index 670904b..3101ff7 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -88,7 +88,7 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *name, con
 	git_remote *remote;
 
 	/* name is optional */
-	assert(out && repo && url);
+	assert(out && url);
 
 	remote = git__calloc(1, sizeof(git_remote));
 	GITERR_CHECK_ALLOC(remote);
@@ -289,6 +289,11 @@ int git_remote_save(const git_remote *remote)
 
 	assert(remote);
 
+	if (!remote->repo) {
+		giterr_set(GITERR_INVALID, "Can't save a dangling remote.");
+		return GIT_ERROR;
+	}
+
 	if ((error = ensure_remote_name_is_valid(remote->name)) < 0)
 		return error;
 
@@ -543,7 +548,7 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur
 
 	assert(remote);
 
-	if (!proxy_url)
+	if (!proxy_url || !remote->repo)
 		return -1;
 
 	*proxy_url = NULL;
@@ -745,6 +750,11 @@ int git_remote_update_tips(git_remote *remote)
 
 	assert(remote);
 
+	if (!remote->repo) {
+		giterr_set(GITERR_INVALID, "Can't update tips on a dangling remote.");
+		return GIT_ERROR;
+	}
+
 	spec = &remote->fetch;
 	
 	if (git_repository_odb__weakptr(&odb, remote->repo) < 0)
@@ -1293,49 +1303,51 @@ int git_remote_rename(
 
 	assert(remote && new_name);
 
-	if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0)
-		return error;
-
 	if ((error = ensure_remote_name_is_valid(new_name)) < 0)
 		return error;
 
-	if (!remote->name) {
-		if ((error = rename_fetch_refspecs(
-			remote,
-			new_name,
-			callback,
-			payload)) < 0)
+	if (remote->repo) {
+		if ((error = ensure_remote_doesnot_exist(remote->repo, new_name)) < 0)
 			return error;
 
-		remote->name = git__strdup(new_name);
+		if (!remote->name) {
+			if ((error = rename_fetch_refspecs(
+				remote,
+				new_name,
+				callback,
+				payload)) < 0)
+				return error;
 
-		return git_remote_save(remote);
-	}
+			remote->name = git__strdup(new_name);
 
-	if ((error = rename_remote_config_section(
-		remote->repo,
-		remote->name,
-		new_name)) < 0)
-			return error;
+			return git_remote_save(remote);
+		}
 
-	if ((error = update_branch_remote_config_entry(
-		remote->repo,
-		remote->name,
-		new_name)) < 0)
-			return error;
+		if ((error = rename_remote_config_section(
+			remote->repo,
+			remote->name,
+			new_name)) < 0)
+				return error;
 
-	if ((error = rename_remote_references(
-		remote->repo,
-		remote->name,
-		new_name)) < 0)
-			return error;
+		if ((error = update_branch_remote_config_entry(
+			remote->repo,
+			remote->name,
+			new_name)) < 0)
+				return error;
 
-	if ((error = rename_fetch_refspecs(
-		remote,
-		new_name,
-		callback,
-		payload)) < 0)
-		return error;
+		if ((error = rename_remote_references(
+			remote->repo,
+			remote->name,
+			new_name)) < 0)
+				return error;
+
+		if ((error = rename_fetch_refspecs(
+			remote,
+			new_name,
+			callback,
+			payload)) < 0)
+			return error;
+	}
 
 	git__free(remote->name);
 	remote->name = git__strdup(new_name);
diff --git a/tests-clar/network/remotes.c b/tests-clar/network/remotes.c
index 70df001..d3f9ff8 100644
--- a/tests-clar/network/remotes.c
+++ b/tests-clar/network/remotes.c
@@ -326,3 +326,13 @@ void test_network_remotes__check_structure_version(void)
 	err = giterr_last();
 	cl_assert_equal_i(GITERR_INVALID, err->klass);
 }
+
+void test_network_remotes__dangling(void)
+{
+	cl_git_pass(git_remote_new(&_remote, NULL, "upstream", "git://github.com/libgit2/libgit2", NULL));
+	cl_git_fail(git_remote_save(_remote));
+	cl_git_fail(git_remote_update_tips(_remote));
+
+	cl_git_pass(git_remote_rename(_remote, "newname", NULL, NULL));
+	cl_assert_equal_s(git_remote_name(_remote), "newname");
+}