Commit Diff


commit - 300ea75439b394ec49d0c1fa52997bafe208fa58
commit + 132af4a5fe242aab94fc8049abfb80888c26395f
blob - 8560ea5c09c6270970313026296fcfd2db1938be
blob + 02dba0611ec49e96e7b8bcaf78fe8563f3b23dfb
--- got/got.1
+++ got/got.1
@@ -195,7 +195,7 @@ files of the cloned repository to store the
 .Ar repository-url
 and
 .Ar branch
-for future use by
+arguments for future use by
 .Cm got fetch
 or
 .Xr git-fetch 1 .
blob - dc1e82d384f2df7cfb6e25b766911671ad36b60b
blob + 4c56b96c153df47ae9d07b608972fe5625f79d5e
--- got/got.c
+++ got/got.c
@@ -1164,19 +1164,40 @@ create_wanted_ref(const char *refname, struct got_obje
 static const struct got_error *
 create_gotconfig(const char *proto, const char *host, const char *port,
     const char *remote_repo_path, const char *default_branch,
-    int fetch_all_branches, int mirror_references, struct got_repository *repo)
+    struct got_pathlist_head *wanted_branches, int mirror_references,
+    struct got_repository *repo)
 {
 	const struct got_error *err = NULL;
 	char *gotconfig_path = NULL;
 	char *gotconfig = NULL;
 	FILE *gotconfig_file = NULL;
 	const char *branchname = NULL;
+	char *branches = NULL;
 	ssize_t n;
 
-	if (default_branch) {
+	if (!TAILQ_EMPTY(wanted_branches)) {
+		struct got_pathlist_entry *pe;
+		TAILQ_FOREACH(pe, wanted_branches, entry) {
+			char *s;
+			branchname = pe->path;
+			if (strncmp(branchname, "refs/heads/", 11) == 0)
+				branchname += 11;
+			if (asprintf(&s, "%s\"%s\" ",
+			    branches ? branches : "", branchname) == -1) {
+				err = got_error_from_errno("asprintf");
+				goto done;
+			}
+			free(branches);
+			branches = s;
+		}
+	} else if (default_branch) {
 		branchname = default_branch;
 		if (strncmp(branchname, "refs/heads/", 11) == 0)
 			branchname += 11;
+		if (asprintf(&branches, "\"%s\" ", branchname) == -1) {
+			err = got_error_from_errno("asprintf");
+			goto done;
+		}
 	}
 
 	/* Create got.conf(5). */
@@ -1201,10 +1222,8 @@ create_gotconfig(const char *proto, const char *host, 
 	    "}\n",
 	    GOT_FETCH_DEFAULT_REMOTE_NAME, host, proto,
 	    port ? "\tport " : "", port ? port : "", port ? "\n" : "",
-	    remote_repo_path,
-	    branchname ? "\tbranch { \"" : "",
-	    branchname ? branchname : "", 
-	    branchname ? "\" }\n" : "", 
+	    remote_repo_path, branches ? "\tbranch { " : "",
+	    branches ? branches : "", branches ? "}\n" : "", 
 	    mirror_references ? "\tmirror-references yes\n" : "") == -1) {
 		err = got_error_from_errno("asprintf");
 		goto done;
@@ -1219,17 +1238,21 @@ done:
 	if (gotconfig_file && fclose(gotconfig_file) == EOF && err == NULL)
 		err = got_error_from_errno2("fclose", gotconfig_path);
 	free(gotconfig_path);
+	free(branches);
 	return err;
 }
 
 static const struct got_error *
 create_gitconfig(const char *git_url, const char *default_branch,
-    int fetch_all_branches, int mirror_references, struct got_repository *repo)
+    int fetch_all_branches, struct got_pathlist_head *wanted_branches,
+    int mirror_references, struct got_repository *repo)
 {
 	const struct got_error *err = NULL;
 	char *gitconfig_path = NULL;
 	char *gitconfig = NULL;
 	FILE *gitconfig_file = NULL;
+	char *branches = NULL;
+	const char *branchname, *mirror = NULL;
 	ssize_t n;
 
 	/* Create a config file Git can understand. */
@@ -1244,28 +1267,38 @@ create_gitconfig(const char *git_url, const char *defa
 		goto done;
 	}
 	if (mirror_references) {
-		if (asprintf(&gitconfig,
-		    "[remote \"%s\"]\n"
-		    "\turl = %s\n"
-		    "\tfetch = +refs/*:refs/*\n"
-		    "\tmirror = true\n",
-		    GOT_FETCH_DEFAULT_REMOTE_NAME, git_url) == -1) {
-			err = got_error_from_errno("asprintf");
+		mirror = "\tmirror = true\n";
+		branches = strdup("\tfetch = +refs/*:refs/*\n");
+		if (branches == NULL) {
+			err = got_error_from_errno("strdup");
 			goto done;
 		}
 	} else if (fetch_all_branches) {
-		if (asprintf(&gitconfig,
-		    "[remote \"%s\"]\n"
-		    "\turl = %s\n"
+		if (asprintf(&branches,
 		    "\tfetch = +refs/heads/*:refs/remotes/%s/*\n",
-		    GOT_FETCH_DEFAULT_REMOTE_NAME, git_url,
 		    GOT_FETCH_DEFAULT_REMOTE_NAME) == -1) {
 			err = got_error_from_errno("asprintf");
 			goto done;
+		}
+	} else if (!TAILQ_EMPTY(wanted_branches)) {
+		struct got_pathlist_entry *pe;
+		TAILQ_FOREACH(pe, wanted_branches, entry) {
+			char *s;
+			branchname = pe->path;
+			if (strncmp(branchname, "refs/heads/", 11) == 0)
+				branchname += 11;
+			if (asprintf(&s,
+			    "%s\tfetch = +refs/heads/%s:refs/remotes/%s/%s\n",
+			    branches ? branches : "",
+			    branchname, GOT_FETCH_DEFAULT_REMOTE_NAME,
+			    branchname) == -1) {
+				err = got_error_from_errno("asprintf");
+				goto done;
+			}
+			free(branches);
+			branches = s;
 		}
 	} else {
-		const char *branchname;
-
 		/*
 		 * If the server specified a default branch, use just that one.
 		 * Otherwise fall back to fetching all branches on next fetch.
@@ -1276,16 +1309,23 @@ create_gitconfig(const char *git_url, const char *defa
 				branchname += 11;
 		} else
 			branchname = "*"; /* fall back to all branches */
-		if (asprintf(&gitconfig,
-		    "[remote \"%s\"]\n"
-		    "\turl = %s\n"
+		if (asprintf(&branches,
 		    "\tfetch = +refs/heads/%s:refs/remotes/%s/%s\n",
-		    GOT_FETCH_DEFAULT_REMOTE_NAME, git_url,
 		    branchname, GOT_FETCH_DEFAULT_REMOTE_NAME,
 		    branchname) == -1) {
 			err = got_error_from_errno("asprintf");
 			goto done;
 		}
+	}
+	if (asprintf(&gitconfig,
+	    "[remote \"%s\"]\n"
+	    "\turl = %s\n"
+	    "%s"
+	    "%s",
+	    GOT_FETCH_DEFAULT_REMOTE_NAME, git_url, branches ? branches : "",
+	    mirror ? mirror : "") == -1) {
+		err = got_error_from_errno("asprintf");
+		goto done;
 	}
 	n = fwrite(gitconfig, 1, strlen(gitconfig), gitconfig_file);
 	if (n != strlen(gitconfig)) {
@@ -1296,6 +1336,7 @@ done:
 	if (gitconfig_file && fclose(gitconfig_file) == EOF && err == NULL)
 		err = got_error_from_errno2("fclose", gitconfig_path);
 	free(gitconfig_path);
+	free(branches);
 	return err;
 }
 
@@ -1332,13 +1373,13 @@ create_config_files(const char *proto, const char *hos
 
 	/* Create got.conf(5). */
 	err = create_gotconfig(proto, host, port, remote_repo_path,
-	    default_branch, fetch_all_branches, mirror_references, repo);
+	    default_branch, wanted_branches, mirror_references, repo);
 	if (err)
 		return err;
 
 	/* Create a config file Git can understand. */
 	return create_gitconfig(git_url, default_branch, fetch_all_branches,
-	    mirror_references, repo);
+	    wanted_branches, mirror_references, repo);
 }
 
 static const struct got_error *
blob - 256c4fc96eab70d803e3a8535f61ceb993785db3
blob + cf7f3aca59153463bc475a9b2dbb9cc872537bc8
--- regress/cmdline/clone.sh
+++ regress/cmdline/clone.sh
@@ -657,7 +657,78 @@ EOF
 	url = ssh://127.0.0.1$testroot/repo
 	fetch = +refs/*:refs/*
 	mirror = true
+EOF
+	cmp -s $testroot/repo-clone/config $testroot/config.expected
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/config.expected \
+			$testroot/repo-clone/config
+	fi
+	test_done "$testroot" "$ret"
+}
+
+test_clone_multiple_branches() {
+	local testroot=`test_init clone_multiple_branches`
+	local testurl=ssh://127.0.0.1/$testroot
+	local commit_id=`git_show_head $testroot/repo`
+
+	got branch -r $testroot/repo -c $commit_id foo
+	got branch -r $testroot/repo -c $commit_id bar
+
+	got clone -q -b foo -b bar $testurl/repo $testroot/repo-clone
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		echo "got clone command failed unexpectedly" >&2
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	got ref -l -r $testroot/repo-clone > $testroot/stdout
+
+	echo "HEAD: refs/heads/foo" > $testroot/stdout.expected
+	echo "refs/heads/bar: $commit_id" >> $testroot/stdout.expected
+	echo "refs/heads/foo: $commit_id" >> $testroot/stdout.expected
+	echo "refs/remotes/origin/bar: $commit_id" \
+		>> $testroot/stdout.expected
+	echo "refs/remotes/origin/foo: $commit_id" \
+		>> $testroot/stdout.expected
+
+	cmp -s $testroot/stdout $testroot/stdout.expected
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/stdout.expected $testroot/stdout
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	cat > $testroot/got.conf.expected <<EOF
+remote "origin" {
+	server 127.0.0.1
+	protocol ssh
+	repository "$testroot/repo"
+	branch { "foo" "bar" }
+}
 EOF
+	cmp -s $testroot/repo-clone/got.conf $testroot/got.conf.expected
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		diff -u $testroot/got.conf.expected \
+			$testroot/repo-clone/got.conf
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	cat > $testroot/config.expected <<EOF
+[core]
+	repositoryformatversion = 0
+	filemode = true
+	bare = true
+
+[remote "origin"]
+	url = ssh://127.0.0.1$testroot/repo
+	fetch = +refs/heads/foo:refs/remotes/origin/foo
+	fetch = +refs/heads/bar:refs/remotes/origin/bar
+EOF
 	cmp -s $testroot/repo-clone/config $testroot/config.expected
 	ret="$?"
 	if [ "$ret" != "0" ]; then
@@ -677,3 +748,4 @@ run_test test_clone_mirror_all
 run_test test_clone_reference
 run_test test_clone_branch_and_reference
 run_test test_clone_reference_mirror
+run_test test_clone_multiple_branches