mirror of
				https://git.proxmox.com/git/libgit2
				synced 2025-11-04 12:12:46 +00:00 
			
		
		
		
	Merge pull request #1222 from scunz/clone_branch
Switch to specified branch during clone
This commit is contained in:
		
						commit
						e2d2c6e57d
					
				@ -57,6 +57,8 @@ GIT_BEGIN_DECL
 | 
			
		||||
 *   the origin remote before the fetch is initiated.
 | 
			
		||||
 * - `remote_autotag` may be used to specify the autotag setting before the
 | 
			
		||||
 *   initial fetch.
 | 
			
		||||
 * - `checkout_branch` gives the name of the branch to checkout. NULL means
 | 
			
		||||
 *   use the remote's HEAD.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
typedef struct git_clone_options {
 | 
			
		||||
@ -76,10 +78,11 @@ typedef struct git_clone_options {
 | 
			
		||||
	git_transport *transport;
 | 
			
		||||
	git_remote_callbacks *remote_callbacks;
 | 
			
		||||
	git_remote_autotag_option_t remote_autotag;
 | 
			
		||||
	const char* checkout_branch;
 | 
			
		||||
} git_clone_options;
 | 
			
		||||
 | 
			
		||||
#define GIT_CLONE_OPTIONS_VERSION 1
 | 
			
		||||
#define GIT_CLONE_OPTIONS_INIT {GIT_CLONE_OPTIONS_VERSION, {GIT_CHECKOUT_OPTS_VERSION, GIT_CHECKOUT_SAFE}}
 | 
			
		||||
#define GIT_CLONE_OPTIONS_INIT {GIT_CLONE_OPTIONS_VERSION, {GIT_CHECKOUT_OPTS_VERSION, GIT_CHECKOUT_SAFE_CREATE}}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Clone a remote repository, and checkout the branch pointed to by the remote
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										35
									
								
								src/clone.c
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								src/clone.c
									
									
									
									
									
								
							@ -29,7 +29,7 @@ static int create_branch(
 | 
			
		||||
	const char *name)
 | 
			
		||||
{
 | 
			
		||||
	git_commit *head_obj = NULL;
 | 
			
		||||
	git_reference *branch_ref;
 | 
			
		||||
	git_reference *branch_ref = NULL;
 | 
			
		||||
	int error;
 | 
			
		||||
 | 
			
		||||
	/* Find the target commit */
 | 
			
		||||
@ -260,6 +260,32 @@ cleanup:
 | 
			
		||||
	return retcode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int update_head_to_branch(
 | 
			
		||||
		git_repository *repo,
 | 
			
		||||
		const git_clone_options *options)
 | 
			
		||||
{
 | 
			
		||||
	int retcode;
 | 
			
		||||
	git_buf remote_branch_name = GIT_BUF_INIT;
 | 
			
		||||
	git_reference* remote_ref = NULL;
 | 
			
		||||
	
 | 
			
		||||
	assert(options->checkout_branch);
 | 
			
		||||
 | 
			
		||||
	if ((retcode = git_buf_printf(&remote_branch_name, GIT_REFS_REMOTES_DIR "%s/%s",
 | 
			
		||||
		options->remote_name, options->checkout_branch)) < 0 )
 | 
			
		||||
		goto cleanup;
 | 
			
		||||
 | 
			
		||||
	if ((retcode = git_reference_lookup(&remote_ref, repo, git_buf_cstr(&remote_branch_name))) < 0)
 | 
			
		||||
		goto cleanup;
 | 
			
		||||
 | 
			
		||||
	retcode = update_head_to_new_branch(repo, git_reference_target(remote_ref),
 | 
			
		||||
		options->checkout_branch);
 | 
			
		||||
 | 
			
		||||
cleanup:
 | 
			
		||||
	git_reference_free(remote_ref);
 | 
			
		||||
	git_buf_free(&remote_branch_name);
 | 
			
		||||
	return retcode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * submodules?
 | 
			
		||||
 */
 | 
			
		||||
@ -331,8 +357,13 @@ static int setup_remotes_and_fetch(
 | 
			
		||||
						options->fetch_progress_payload)) {
 | 
			
		||||
				/* Create "origin/foo" branches for all remote branches */
 | 
			
		||||
				if (!git_remote_update_tips(origin)) {
 | 
			
		||||
					/* Point HEAD to the requested branch */
 | 
			
		||||
					if (options->checkout_branch) {
 | 
			
		||||
						if (!update_head_to_branch(repo, options))
 | 
			
		||||
							retcode = 0;
 | 
			
		||||
					}
 | 
			
		||||
					/* Point HEAD to the same ref as the remote's head */
 | 
			
		||||
					if (!update_head_to_remote(repo, origin)) {
 | 
			
		||||
					else if (!update_head_to_remote(repo, origin)) {
 | 
			
		||||
						retcode = 0;
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
@ -7,6 +7,8 @@
 | 
			
		||||
 | 
			
		||||
static git_clone_options g_options;
 | 
			
		||||
static git_repository *g_repo;
 | 
			
		||||
static git_reference* g_ref;
 | 
			
		||||
static git_remote* g_remote;
 | 
			
		||||
 | 
			
		||||
void test_clone_nonetwork__initialize(void)
 | 
			
		||||
{
 | 
			
		||||
@ -27,6 +29,16 @@ void test_clone_nonetwork__cleanup(void)
 | 
			
		||||
		g_repo = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (g_ref) {
 | 
			
		||||
		git_reference_free(g_ref);
 | 
			
		||||
		g_ref = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (g_remote) {
 | 
			
		||||
		git_remote_free(g_remote);
 | 
			
		||||
		g_remote = NULL;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cl_fixture_cleanup("./foo");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -73,66 +85,51 @@ void test_clone_nonetwork__fail_with_already_existing_but_non_empty_directory(vo
 | 
			
		||||
 | 
			
		||||
void test_clone_nonetwork__custom_origin_name(void)
 | 
			
		||||
{
 | 
			
		||||
	git_remote *remote;
 | 
			
		||||
 | 
			
		||||
	g_options.remote_name = "my_origin";
 | 
			
		||||
	cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options));
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_remote_load(&remote, g_repo, "my_origin"));
 | 
			
		||||
 | 
			
		||||
	git_remote_free(remote);
 | 
			
		||||
	cl_git_pass(git_remote_load(&g_remote, g_repo, "my_origin"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_clone_nonetwork__custom_push_url(void)
 | 
			
		||||
{
 | 
			
		||||
	git_remote *remote;
 | 
			
		||||
	const char *url = "http://example.com";
 | 
			
		||||
 | 
			
		||||
	g_options.pushurl = url;
 | 
			
		||||
	cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options));
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_remote_load(&remote, g_repo, "origin"));
 | 
			
		||||
	cl_assert_equal_s(url, git_remote_pushurl(remote));
 | 
			
		||||
 | 
			
		||||
	git_remote_free(remote);
 | 
			
		||||
	cl_git_pass(git_remote_load(&g_remote, g_repo, "origin"));
 | 
			
		||||
	cl_assert_equal_s(url, git_remote_pushurl(g_remote));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_clone_nonetwork__custom_fetch_spec(void)
 | 
			
		||||
{
 | 
			
		||||
	git_remote *remote;
 | 
			
		||||
	git_reference *master;
 | 
			
		||||
	const git_refspec *actual_fs;
 | 
			
		||||
	const char *spec = "+refs/heads/master:refs/heads/foo";
 | 
			
		||||
 | 
			
		||||
	g_options.fetch_spec = spec;
 | 
			
		||||
	cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options));
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_remote_load(&remote, g_repo, "origin"));
 | 
			
		||||
	actual_fs = git_remote_fetchspec(remote);
 | 
			
		||||
	cl_git_pass(git_remote_load(&g_remote, g_repo, "origin"));
 | 
			
		||||
	actual_fs = git_remote_fetchspec(g_remote);
 | 
			
		||||
	cl_assert_equal_s("refs/heads/master", git_refspec_src(actual_fs));
 | 
			
		||||
	cl_assert_equal_s("refs/heads/foo", git_refspec_dst(actual_fs));
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/foo"));
 | 
			
		||||
	git_reference_free(master);
 | 
			
		||||
 | 
			
		||||
	git_remote_free(remote);
 | 
			
		||||
	cl_git_pass(git_reference_lookup(&g_ref, g_repo, "refs/heads/foo"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_clone_nonetwork__custom_push_spec(void)
 | 
			
		||||
{
 | 
			
		||||
	git_remote *remote;
 | 
			
		||||
	const git_refspec *actual_fs;
 | 
			
		||||
	const char *spec = "+refs/heads/master:refs/heads/foo";
 | 
			
		||||
 | 
			
		||||
	g_options.push_spec = spec;
 | 
			
		||||
	cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options));
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_remote_load(&remote, g_repo, "origin"));
 | 
			
		||||
	actual_fs = git_remote_pushspec(remote);
 | 
			
		||||
	cl_git_pass(git_remote_load(&g_remote, g_repo, "origin"));
 | 
			
		||||
	actual_fs = git_remote_pushspec(g_remote);
 | 
			
		||||
	cl_assert_equal_s("refs/heads/master", git_refspec_src(actual_fs));
 | 
			
		||||
	cl_assert_equal_s("refs/heads/foo", git_refspec_dst(actual_fs));
 | 
			
		||||
 | 
			
		||||
	git_remote_free(remote);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_clone_nonetwork__custom_autotag(void)
 | 
			
		||||
@ -167,3 +164,14 @@ void test_clone_nonetwork__can_prevent_the_checkout_of_a_standard_repo(void)
 | 
			
		||||
	git_buf_free(&path);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void test_clone_nonetwork__can_checkout_given_branch(void)
 | 
			
		||||
{
 | 
			
		||||
	g_options.checkout_branch = "test";
 | 
			
		||||
	cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options));
 | 
			
		||||
 | 
			
		||||
	cl_assert_equal_i(0, git_repository_head_orphan(g_repo));
 | 
			
		||||
 | 
			
		||||
	cl_git_pass(git_repository_head(&g_ref, g_repo));
 | 
			
		||||
	cl_assert_equal_s(git_reference_name(g_ref), "refs/heads/test");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user