Commit 94e345826e849d48d0225418dd969cf0e18e34c5

Edward Thomson 2020-10-11T11:32:04

Merge pull request #5651 from libgit2/ethomson/clone_branch clone: update origin's HEAD

diff --git a/src/clone.c b/src/clone.c
index a662a76..a93ec47 100644
--- a/src/clone.c
+++ b/src/clone.c
@@ -162,6 +162,55 @@ done:
 	return error;
 }
 
+static int update_remote_head(
+	git_repository *repo,
+	git_remote *remote,
+	git_buf *target,
+	const char *reflog_message)
+{
+	git_refspec *refspec;
+	git_reference *remote_head = NULL;
+	git_buf remote_head_name = GIT_BUF_INIT;
+	git_buf remote_branch_name = GIT_BUF_INIT;
+	int error;
+
+	/* Determine the remote tracking ref name from the local branch */
+	refspec = git_remote__matching_refspec(remote, git_buf_cstr(target));
+
+	if (refspec == NULL) {
+		git_error_set(GIT_ERROR_NET, "the remote's default branch does not fit the refspec configuration");
+		error = GIT_EINVALIDSPEC;
+		goto cleanup;
+	}
+
+	if ((error = git_refspec_transform(
+		&remote_branch_name,
+		refspec,
+		git_buf_cstr(target))) < 0)
+		goto cleanup;
+
+	if ((error = git_buf_printf(&remote_head_name,
+		"%s%s/%s",
+		GIT_REFS_REMOTES_DIR,
+		git_remote_name(remote),
+		GIT_HEAD_FILE)) < 0)
+		goto cleanup;
+
+	error = git_reference_symbolic_create(
+		&remote_head,
+		repo,
+		git_buf_cstr(&remote_head_name),
+		git_buf_cstr(&remote_branch_name),
+		true,
+		reflog_message);
+
+cleanup:
+	git_reference_free(remote_head);
+	git_buf_dispose(&remote_branch_name);
+	git_buf_dispose(&remote_head_name);
+	return error;
+}
+
 static int update_head_to_remote(
 		git_repository *repo,
 		git_remote *remote,
@@ -169,10 +218,8 @@ static int update_head_to_remote(
 {
 	int error = 0;
 	size_t refs_len;
-	git_refspec *refspec;
 	const git_remote_head *remote_head, **refs;
 	const git_oid *remote_head_id;
-	git_buf remote_branch_name = GIT_BUF_INIT;
 	git_buf branch = GIT_BUF_INIT;
 
 	if ((error = git_remote_ls(&refs, &refs_len, remote)) < 0)
@@ -195,19 +242,7 @@ static int update_head_to_remote(
 		goto cleanup;
 	}
 
-	refspec = git_remote__matching_refspec(remote, git_buf_cstr(&branch));
-
-	if (refspec == NULL) {
-		git_error_set(GIT_ERROR_NET, "the remote's default branch does not fit the refspec configuration");
-		error = GIT_EINVALIDSPEC;
-		goto cleanup;
-	}
-
-	/* Determine the remote tracking ref name from the local branch */
-	if ((error = git_refspec_transform(
-		&remote_branch_name,
-		refspec,
-		git_buf_cstr(&branch))) < 0)
+	if ((error = update_remote_head(repo, remote, &branch, reflog_message)) < 0)
 		goto cleanup;
 
 	error = update_head_to_new_branch(
@@ -217,7 +252,6 @@ static int update_head_to_remote(
 		reflog_message);
 
 cleanup:
-	git_buf_dispose(&remote_branch_name);
 	git_buf_dispose(&branch);
 
 	return error;
diff --git a/tests/online/clone.c b/tests/online/clone.c
index 9107956..c62baac 100644
--- a/tests/online/clone.c
+++ b/tests/online/clone.c
@@ -176,7 +176,7 @@ static int fetch_progress(const git_indexer_progress *stats, void *payload)
 void test_online_clone__can_checkout_a_cloned_repo(void)
 {
 	git_buf path = GIT_BUF_INIT;
-	git_reference *head;
+	git_reference *head, *remote_head;
 	bool checkout_progress_cb_was_called = false,
 		  fetch_progress_cb_was_called = false;
 
@@ -195,9 +195,14 @@ void test_online_clone__can_checkout_a_cloned_repo(void)
 	cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(head));
 	cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head));
 
+	cl_git_pass(git_reference_lookup(&remote_head, g_repo, "refs/remotes/origin/HEAD"));
+	cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(remote_head));
+	cl_assert_equal_s("refs/remotes/origin/master", git_reference_symbolic_target(remote_head));
+
 	cl_assert_equal_i(true, checkout_progress_cb_was_called);
 	cl_assert_equal_i(true, fetch_progress_cb_was_called);
 
+	git_reference_free(remote_head);
 	git_reference_free(head);
 	git_buf_dispose(&path);
 }