Commit 0c8b29c50669cb8958428fbf923f02a5b69184db

Stefan Sperling 2021-01-05T17:22:14

add a 'fetch-all-branches' configuration setting to got.conf(5) Set fetch-all-branches in the got.conf(5) file created by 'got clone -a' in order to make a future 'got fetch' act like 'got fetch -a' by default.

diff --git a/got/got.1 b/got/got.1
index 02dba06..0c9b093 100644
--- a/got/got.1
+++ b/got/got.1
@@ -362,6 +362,8 @@ are as follows:
 Fetch all branches from the remote repository's
 .Dq refs/heads/
 reference namespace.
+This option can be enabled by default for specific repositories in
+.Xr got.conf 5 .
 If this option is not specified, a branch resolved via the remote
 repository's HEAD reference will be fetched.
 Cannot be used together with the
diff --git a/got/got.c b/got/got.c
index 4c56b96..53829fb 100644
--- a/got/got.c
+++ b/got/got.c
@@ -1164,8 +1164,8 @@ create_wanted_ref(const char *refname, struct got_object_id *id,
 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,
-    struct got_pathlist_head *wanted_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 *gotconfig_path = NULL;
@@ -1175,7 +1175,7 @@ create_gotconfig(const char *proto, const char *host, const char *port,
 	char *branches = NULL;
 	ssize_t n;
 
-	if (!TAILQ_EMPTY(wanted_branches)) {
+	if (!fetch_all_branches && !TAILQ_EMPTY(wanted_branches)) {
 		struct got_pathlist_entry *pe;
 		TAILQ_FOREACH(pe, wanted_branches, entry) {
 			char *s;
@@ -1190,7 +1190,7 @@ create_gotconfig(const char *proto, const char *host, const char *port,
 			free(branches);
 			branches = s;
 		}
-	} else if (default_branch) {
+	} else if (!fetch_all_branches && default_branch) {
 		branchname = default_branch;
 		if (strncmp(branchname, "refs/heads/", 11) == 0)
 			branchname += 11;
@@ -1219,12 +1219,14 @@ create_gotconfig(const char *proto, const char *host, const char *port,
 	    "\trepository \"%s\"\n"
 	    "%s%s%s"
 	    "%s"
+	    "%s"
 	    "}\n",
 	    GOT_FETCH_DEFAULT_REMOTE_NAME, host, proto,
 	    port ? "\tport " : "", port ? port : "", port ? "\n" : "",
 	    remote_repo_path, branches ? "\tbranch { " : "",
 	    branches ? branches : "", branches ? "}\n" : "", 
-	    mirror_references ? "\tmirror-references yes\n" : "") == -1) {
+	    mirror_references ? "\tmirror-references yes\n" : "",
+	    fetch_all_branches ? "\tfetch-all-branches yes\n" : "") == -1) {
 		err = got_error_from_errno("asprintf");
 		goto done;
 	}
@@ -1373,7 +1375,8 @@ create_config_files(const char *proto, const char *host, const char *port,
 
 	/* Create got.conf(5). */
 	err = create_gotconfig(proto, host, port, remote_repo_path,
-	    default_branch, wanted_branches, mirror_references, repo);
+	    default_branch, fetch_all_branches, wanted_branches,
+	    mirror_references, repo);
 	if (err)
 		return err;
 
@@ -2209,12 +2212,13 @@ cmd_fetch(int argc, char *argv[])
 		goto done;
 	}
 
-	if (TAILQ_EMPTY(&wanted_branches) && remote->nbranches > 0) {
+	if (TAILQ_EMPTY(&wanted_branches)) {
+		if (!fetch_all_branches)
+			fetch_all_branches = remote->fetch_all_branches;
 		for (i = 0; i < remote->nbranches; i++) {
 			got_pathlist_append(&wanted_branches,
 			    remote->branches[i], NULL);
 		}
-
 	}
 
 	error = got_fetch_parse_uri(&proto, &host, &port, &server_path,
diff --git a/got/got.conf.5 b/got/got.conf.5
index 4995cf2..b4fe08c 100644
--- a/got/got.conf.5
+++ b/got/got.conf.5
@@ -114,6 +114,17 @@ The list of branches specified here can be overridden at the
 command line with the
 .Fl b
 option.
+.It Ic fetch-all-branches Ar yes | no
+This option controls whether
+.Cm got fetch
+will fetch all branches from the remote repository by default.
+If enabled, this behaviour can be overridden at the
+.Cm got fetch
+command line with the
+.Fl b
+option, and any
+.Cm branch
+configuration settings for this remote repository will be ignored.
 .It Ic mirror-references Ar yes | no
 This option controls the behaviour of
 .Cm got fetch
diff --git a/include/got_repository.h b/include/got_repository.h
index 1b274cc..8cc337b 100644
--- a/include/got_repository.h
+++ b/include/got_repository.h
@@ -61,6 +61,12 @@ struct got_remote_repo {
 	 */
 	int mirror_references;
 
+	/*
+	 * If set, fetch all branches by default and ignore the list of
+	 * branches below.
+	 */
+	int fetch_all_branches;
+
 	/* Branches to fetch by default. */
 	int nbranches;
 	char **branches;
diff --git a/lib/got_lib_privsep.h b/lib/got_lib_privsep.h
index f4815b5..fba84c4 100644
--- a/lib/got_lib_privsep.h
+++ b/lib/got_lib_privsep.h
@@ -378,6 +378,7 @@ struct got_imsg_remote {
 	size_t name_len;
 	size_t url_len;
 	int mirror_references;
+	int fetch_all_branches;
 	int nbranches;
 
 	/* Followed by name_len + url_len data bytes. */
diff --git a/lib/privsep.c b/lib/privsep.c
index a17a878..a4c526b 100644
--- a/lib/privsep.c
+++ b/lib/privsep.c
@@ -1889,6 +1889,7 @@ got_privsep_recv_gitconfig_remotes(struct got_remote_repo **remotes,
 				break;
 			}
 			remote->mirror_references = iremote.mirror_references;
+			remote->fetch_all_branches = iremote.fetch_all_branches;
 			remote->nbranches = 0;
 			remote->branches = NULL;
 			(*nremotes)++;
@@ -2095,6 +2096,7 @@ got_privsep_recv_gotconfig_remotes(struct got_remote_repo **remotes,
 				break;
 			}
 			remote->mirror_references = iremote.mirror_references;
+			remote->fetch_all_branches = iremote.fetch_all_branches;
 			if (iremote.nbranches > 0) {
 				remote->branches = recallocarray(NULL, 0,
 				    iremote.nbranches, sizeof(char *));
diff --git a/libexec/got-read-gotconfig/got-read-gotconfig.c b/libexec/got-read-gotconfig/got-read-gotconfig.c
index 631e112..70e9932 100644
--- a/libexec/got-read-gotconfig/got-read-gotconfig.c
+++ b/libexec/got-read-gotconfig/got-read-gotconfig.c
@@ -153,6 +153,7 @@ send_gotconfig_remotes(struct imsgbuf *ibuf,
 
 		iremote.nbranches = nbranches;
 		iremote.mirror_references = repo->mirror_references;
+		iremote.fetch_all_branches = repo->fetch_all_branches;
 
 		iremote.name_len = strlen(repo->name);
 		len += iremote.name_len;
diff --git a/libexec/got-read-gotconfig/gotconfig.h b/libexec/got-read-gotconfig/gotconfig.h
index a909f14..212b87b 100644
--- a/libexec/got-read-gotconfig/gotconfig.h
+++ b/libexec/got-read-gotconfig/gotconfig.h
@@ -29,6 +29,7 @@ struct gotconfig_remote_repo {
 	char	*protocol;
 	int	port;
 	int	mirror_references;
+	int	fetch_all_branches;
 	struct	node_branch *branch;
 };
 TAILQ_HEAD(gotconfig_remote_repo_list, gotconfig_remote_repo);
diff --git a/libexec/got-read-gotconfig/parse.y b/libexec/got-read-gotconfig/parse.y
index df2c1d7..07d4556 100644
--- a/libexec/got-read-gotconfig/parse.y
+++ b/libexec/got-read-gotconfig/parse.y
@@ -95,7 +95,7 @@ typedef struct {
 
 %token	ERROR
 %token	REMOTE REPOSITORY SERVER PORT PROTOCOL MIRROR_REFERENCES BRANCH
-%token	AUTHOR
+%token	AUTHOR FETCH_ALL_BRANCHES
 %token	<v.string>	STRING
 %token	<v.number>	NUMBER
 %type	<v.number>	boolean portplain
@@ -197,6 +197,9 @@ remoteopts1	: REPOSITORY STRING {
 		| MIRROR_REFERENCES boolean {
 			remote->mirror_references = $2;
 		}
+		| FETCH_ALL_BRANCHES boolean {
+			remote->fetch_all_branches = $2;
+		}
 		| PORT portplain {
 			remote->port = $2;
 		}
@@ -286,6 +289,7 @@ lookup(char *s)
 	static const struct keywords keywords[] = {
 		{"author",		AUTHOR},
 		{"branch",		BRANCH},
+		{"fetch-all-branches",	FETCH_ALL_BRANCHES},
 		{"mirror-references",	MIRROR_REFERENCES},
 		{"port",		PORT},
 		{"protocol",		PROTOCOL},
diff --git a/regress/cmdline/clone.sh b/regress/cmdline/clone.sh
index cf7f3ac..b36a5f4 100755
--- a/regress/cmdline/clone.sh
+++ b/regress/cmdline/clone.sh
@@ -270,7 +270,7 @@ remote "origin" {
 	server 127.0.0.1
 	protocol ssh
 	repository "$testroot/repo"
-	branch { "master" }
+	fetch-all-branches yes
 }
 EOF
 	cmp -s $testroot/repo-clone/got.conf $testroot/got.conf.expected
@@ -414,8 +414,8 @@ remote "origin" {
 	server 127.0.0.1
 	protocol ssh
 	repository "$testroot/repo"
-	branch { "master" }
 	mirror-references yes
+	fetch-all-branches yes
 }
 EOF
 	cmp -s $testroot/repo-clone/got.conf $testroot/got.conf.expected