Commit 8897f8fe687f11d327be30873480c5d02a6a00a6

Patrick Steinhardt 2017-05-05T09:47:54

remote: reject various actions for detached remotes There are only few actions which actually make sense for a detached remote, like e.g. `git_remote_ls`, `git_remote_prune`. For all the other actions, we have to report an error when the remote has no repository attached to it. This commit does so and implements some tests.

diff --git a/src/remote.c b/src/remote.c
index bbca7ae..86fda5f 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -861,6 +861,11 @@ int git_remote_download(git_remote *remote, const git_strarray *refspecs, const 
 
 	assert(remote);
 
+	if (!remote->repo) {
+		giterr_set(GITERR_INVALID, "cannot download detached remote");
+		return -1;
+	}
+
 	if (opts) {
 		GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
 		cbs = &opts->callbacks;
@@ -2346,6 +2351,11 @@ int git_remote_upload(git_remote *remote, const git_strarray *refspecs, const gi
 
 	assert(remote);
 
+	if (!remote->repo) {
+		giterr_set(GITERR_INVALID, "cannot download detached remote");
+		return -1;
+	}
+
 	if (opts) {
 		cbs = &opts->callbacks;
 		custom_headers = &opts->custom_headers;
@@ -2405,6 +2415,13 @@ int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_
 	const git_strarray *custom_headers = NULL;
 	const git_proxy_options *proxy = NULL;
 
+	assert(remote);
+
+	if (!remote->repo) {
+		giterr_set(GITERR_INVALID, "cannot download detached remote");
+		return -1;
+	}
+
 	if (opts) {
 		GITERR_CHECK_VERSION(&opts->callbacks, GIT_REMOTE_CALLBACKS_VERSION, "git_remote_callbacks");
 		cbs = &opts->callbacks;
diff --git a/tests/online/remotes.c b/tests/online/remotes.c
index a86f2d9..efab63f 100644
--- a/tests/online/remotes.c
+++ b/tests/online/remotes.c
@@ -53,3 +53,36 @@ void test_online_remotes__restricted_refspecs(void)
 
 	cl_git_fail_with(GIT_EINVALIDSPEC, git_clone(&repo, "git://github.com/libgit2/TestGitRepository", "./restrict-refspec", &opts));
 }
+
+void test_online_remotes__detached_remote_fails_downloading(void)
+{
+	git_remote *remote;
+
+	cl_git_pass(git_remote_create_detached(&remote, URL));
+	cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL));
+	cl_git_fail(git_remote_download(remote, NULL, NULL));
+
+	git_remote_free(remote);
+}
+
+void test_online_remotes__detached_remote_fails_uploading(void)
+{
+	git_remote *remote;
+
+	cl_git_pass(git_remote_create_detached(&remote, URL));
+	cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL));
+	cl_git_fail(git_remote_upload(remote, NULL, NULL));
+
+	git_remote_free(remote);
+}
+
+void test_online_remotes__detached_remote_fails_pushing(void)
+{
+	git_remote *remote;
+
+	cl_git_pass(git_remote_create_detached(&remote, URL));
+	cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL));
+	cl_git_fail(git_remote_push(remote, NULL, NULL));
+
+	git_remote_free(remote);
+}