Commit Diff


commit - cad0b9e88686cab44e7532dfaaa0b5cdd47beb10
commit + b8adfa5529205d58ab21c9c8fc76b50068ebbaa2
blob - fd46852d20b5897c487045e6e0c4d99e0bda0508
blob + d21f191972b4fc066ea0888f9cdd02172ef49fde
--- got/got.c
+++ got/got.c
@@ -2094,6 +2094,14 @@ cmd_fetch(int argc, char *argv[])
 	if (remote == NULL) {
 		error = got_error_path(remote_name, GOT_ERR_NO_REMOTE);
 		goto done;
+	}
+
+	if (TAILQ_EMPTY(&wanted_branches) && remote->nbranches > 0) {
+		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,
blob - f1c3eb07dd31dd3a4620452bfdfab1b4119d3c66
blob + 4995cf2a725ee8bd5c325bcf65e0bafcf67f4f87
--- got/got.conf.5
+++ got/got.conf.5
@@ -105,6 +105,15 @@ for details.
 If not specified, the default port of the specified
 .Cm protocol
 will be used.
+.It Ic branch Brq Ar branch ...
+Specify one or more branches which
+.Cm got fetch
+should fetch from the remote repository by default.
+The list of branches specified here can be overridden at the
+.Cm got fetch
+command line with the
+.Fl b
+option.
 .It Ic mirror-references Ar yes | no
 This option controls the behaviour of
 .Cm got fetch
@@ -138,6 +147,7 @@ remote "origin" {
 	server git.gameoftrees.org
 	protocol git
 	repository got
+	branch { "main" }
 }
 .Ed
 .Pp
blob - 2b104798d08e7adbf100ae6c9d7a0877630dacdd
blob + 20f873a5d4df17522f28c52407c564cdb5d0e583
--- include/got_repository.h
+++ include/got_repository.h
@@ -51,15 +51,25 @@ const char *got_repo_get_gitconfig_owner(struct got_re
 struct got_remote_repo {
 	char *name;
 	char *url;
-	
+
 	/*
 	 * If set, references are mirrored 1:1 into the local repository.
 	 * If not set, references are mapped into "refs/remotes/$name/".
 	 */
 	int mirror_references;
+
+	/* Branches to fetch by default. */
+	int nbranches;
+	char **branches;
 };
 
-/* Obtain the list of remote repositories parsed from gitconfig. */ 
+/*
+ * Free data allocated for the specified remote repository.
+ * Do not free the remote_repo pointer itself.
+ */
+void got_repo_free_remote_repo_data(struct got_remote_repo *);
+
+/* Obtain the list of remote repositories parsed from gitconfig. */
 void got_repo_get_gitconfig_remotes(int *, const struct got_remote_repo **,
     struct got_repository *);
 
blob - 51acfb2fde45abd2e9073411ad36ae9a24fed30e
blob + 6c638e9d018fe07c5b7e6949507b353ea5495e3e
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
@@ -377,8 +377,10 @@ struct got_imsg_remote {
 	size_t name_len;
 	size_t url_len;
 	int mirror_references;
+	int nbranches;
 
 	/* Followed by name_len + url_len data bytes. */
+	/* Followed by nbranches GOT_IMSG_GITCONFIG_STR_VAL messages. */
 } __attribute__((__packed__));
 
 /*
blob - d3c83b325581b556b7bca0faa5d7f3fbc611c63b
blob + 7133ec58bdbaf535f13ad65c71428d7eb891a975
--- lib/gotconfig.c
+++ lib/gotconfig.c
@@ -138,10 +138,8 @@ got_gotconfig_free(struct got_gotconfig *conf)
 
 	free(conf->author);
 
-	for (i = 0; i < conf->nremotes; i++) {
-		free(conf->remotes[i].name);
-		free(conf->remotes[i].url);
-	}
+	for (i = 0; i < conf->nremotes; i++)
+		got_repo_free_remote_repo_data(&conf->remotes[i]);
 	free(conf->remotes);
 	free(conf);
 }
blob - 77debd84e15bb4334632363ebe637cfbe88f4202
blob + 0cacbdd05b05c1e5021ca3c240f513d4476a0d8d
--- lib/privsep.c
+++ lib/privsep.c
@@ -1783,6 +1783,18 @@ got_privsep_recv_gitconfig_int(int *val, struct imsgbu
 
 	imsg_free(&imsg);
 	return err;
+}
+
+static void
+free_remote_data(struct got_remote_repo *remote)
+{
+	int i;
+
+	free(remote->name);
+	free(remote->url);
+	for (i = 0; i < remote->nbranches; i++)
+		free(remote->branches[i]);
+	free(remote->branches);
 }
 
 const struct got_error *
@@ -1838,6 +1850,7 @@ got_privsep_recv_gitconfig_remotes(struct got_remote_r
 		switch (imsg.hdr.type) {
 		case GOT_IMSG_GITCONFIG_REMOTE:
 			remote = &(*remotes)[*nremotes];
+			memset(remote, 0, sizeof(*remote));
 			if (datalen < sizeof(iremote)) {
 				err = got_error(GOT_ERR_PRIVSEP_LEN);
 				break;
@@ -1859,10 +1872,12 @@ got_privsep_recv_gitconfig_remotes(struct got_remote_r
 			    iremote.name_len, iremote.url_len);
 			if (remote->url == NULL) {
 				err = got_error_from_errno("strndup");
-				free(remote->name);
+				free_remote_data(remote);
 				break;
 			}
 			remote->mirror_references = iremote.mirror_references;
+			remote->nbranches = 0;
+			remote->branches = NULL;
 			(*nremotes)++;
 			break;
 		default:
@@ -1877,10 +1892,8 @@ got_privsep_recv_gitconfig_remotes(struct got_remote_r
 
 	if (err) {
 		int i;
-		for (i = 0; i < *nremotes; i++) {
-			free((*remotes)[i].name);
-			free((*remotes)[i].url);
-		}
+		for (i = 0; i < *nremotes; i++)
+			free_remote_data(&(*remotes)[i]);
 		free(*remotes);
 		*remotes = NULL;
 		*nremotes = 0;
@@ -1970,6 +1983,7 @@ got_privsep_recv_gotconfig_str(char **str, struct imsg
 	return err;
 }
 
+
 const struct got_error *
 got_privsep_recv_gotconfig_remotes(struct got_remote_repo **remotes,
     int *nremotes, struct imsgbuf *ibuf)
@@ -2025,6 +2039,7 @@ got_privsep_recv_gotconfig_remotes(struct got_remote_r
 		struct got_remote_repo *remote;
 		const size_t min_datalen =
 		    MIN(sizeof(struct got_imsg_error), sizeof(iremote));
+		int i;
 
 		err = got_privsep_recv_imsg(&imsg, ibuf, min_datalen);
 		if (err)
@@ -2041,6 +2056,7 @@ got_privsep_recv_gotconfig_remotes(struct got_remote_r
 			break;
 		case GOT_IMSG_GOTCONFIG_REMOTE:
 			remote = &(*remotes)[*nremotes];
+			memset(remote, 0, sizeof(*remote));
 			if (datalen < sizeof(iremote)) {
 				err = got_error(GOT_ERR_PRIVSEP_LEN);
 				break;
@@ -2062,10 +2078,31 @@ got_privsep_recv_gotconfig_remotes(struct got_remote_r
 			    iremote.name_len, iremote.url_len);
 			if (remote->url == NULL) {
 				err = got_error_from_errno("strndup");
-				free(remote->name);
+				free_remote_data(remote);
 				break;
 			}
 			remote->mirror_references = iremote.mirror_references;
+			if (iremote.nbranches > 0) {
+				remote->branches = recallocarray(NULL, 0,
+				    iremote.nbranches, sizeof(char *));
+				if (remote->branches == NULL) {
+					err = got_error_from_errno("calloc");
+					free_remote_data(remote);
+					break;
+				}
+			}
+			remote->nbranches = 0;
+			for (i = 0; i < iremote.nbranches; i++) {
+				char *branch;
+				err = got_privsep_recv_gotconfig_str(&branch,
+				    ibuf);
+				if (err) {
+					free_remote_data(remote);
+					goto done;
+				}
+				remote->branches[i] = branch;
+				remote->nbranches++;
+			}
 			(*nremotes)++;
 			break;
 		default:
@@ -2077,13 +2114,11 @@ got_privsep_recv_gotconfig_remotes(struct got_remote_r
 		if (err)
 			break;
 	}
-
+done:
 	if (err) {
 		int i;
-		for (i = 0; i < *nremotes; i++) {
-			free((*remotes)[i].name);
-			free((*remotes)[i].url);
-		}
+		for (i = 0; i < *nremotes; i++)
+			free_remote_data(&(*remotes)[i]);
 		free(*remotes);
 		*remotes = NULL;
 		*nremotes = 0;
blob - 4c90acd881a0f23ba1cb6479838a991e6e8eb61f
blob + 5fe931f9c74dc53f1a6814a342b8eefc7d80f439
--- lib/repository.c
+++ lib/repository.c
@@ -681,14 +681,28 @@ got_repo_close(struct got_repository *repo)
 		got_gotconfig_free(repo->gotconfig);
 	free(repo->gitconfig_author_name);
 	free(repo->gitconfig_author_email);
-	for (i = 0; i < repo->ngitconfig_remotes; i++) {
-		free(repo->gitconfig_remotes[i].name);
-		free(repo->gitconfig_remotes[i].url);
-	}
+	for (i = 0; i < repo->ngitconfig_remotes; i++)
+		got_repo_free_remote_repo_data(&repo->gitconfig_remotes[i]);
 	free(repo->gitconfig_remotes);
 	free(repo);
 
 	return err;
+}
+
+void
+got_repo_free_remote_repo_data(struct got_remote_repo *repo)
+{
+	int i;
+
+	free(repo->name);
+	repo->name = NULL;
+	free(repo->url);
+	repo->url = NULL;
+	for (i = 0; i < repo->nbranches; i++)
+		free(repo->branches[i]);
+	free(repo->branches);
+	repo->branches = NULL;
+	repo->nbranches = 0;
 }
 
 const struct got_error *
blob - e7234d40124938d4a98b3294599098e47661c6f5
blob + 631e11236b4eb40c77f4df72632afabd30ee931e
--- libexec/got-read-gotconfig/got-read-gotconfig.c
+++ libexec/got-read-gotconfig/got-read-gotconfig.c
@@ -142,7 +142,16 @@ send_gotconfig_remotes(struct imsgbuf *ibuf,
 		struct got_imsg_remote iremote;
 		size_t len = sizeof(iremote);
 		struct ibuf *wbuf;
+		struct node_branch *branch;
+		int nbranches = 0;
 
+		branch = repo->branch;
+		while (branch) {
+			branch = branch->next;
+			nbranches++;
+		}
+
+		iremote.nbranches = nbranches;
 		iremote.mirror_references = repo->mirror_references;
 
 		iremote.name_len = strlen(repo->name);
@@ -189,6 +198,14 @@ send_gotconfig_remotes(struct imsgbuf *ibuf,
 
 		free(url);
 		url = NULL;
+
+		branch = repo->branch;
+		while (branch) {
+			err = send_gotconfig_str(ibuf, branch->branch_name);
+			if (err)
+				break;
+			branch = branch->next;
+		}
 	}
 
 	free(url);
blob - ab55bd31f17ddbcdf0a483b21903f7e00a588c20
blob + a909f144a9ab2a4715e7975ad3fcbd8764181cde
--- libexec/got-read-gotconfig/gotconfig.h
+++ libexec/got-read-gotconfig/gotconfig.h
@@ -15,6 +15,12 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+struct node_branch {
+	char *branch_name;
+	struct node_branch *next;
+	struct node_branch *tail;
+};
+
 struct gotconfig_remote_repo {
 	TAILQ_ENTRY(gotconfig_remote_repo) entry;
 	char	*name;
@@ -23,6 +29,7 @@ struct gotconfig_remote_repo {
 	char	*protocol;
 	int	port;
 	int	mirror_references;
+	struct	node_branch *branch;
 };
 TAILQ_HEAD(gotconfig_remote_repo_list, gotconfig_remote_repo);
 
blob - aa7193a5915cdb3f05afe31c665b6ac7fbf31480
blob + 2ae503c4da4198a918f6bbb1bed217eb6bbba8b0
--- libexec/got-read-gotconfig/parse.y
+++ libexec/got-read-gotconfig/parse.y
@@ -86,6 +86,7 @@ typedef struct {
 	union {
 		int64_t		 number;
 		char		*string;
+		struct node_branch *branch;
 	} v;
 	int lineno;
 } YYSTYPE;
@@ -93,11 +94,13 @@ typedef struct {
 %}
 
 %token	ERROR
-%token	REMOTE REPOSITORY SERVER PORT PROTOCOL MIRROR_REFERENCES AUTHOR
+%token	REMOTE REPOSITORY SERVER PORT PROTOCOL MIRROR_REFERENCES BRANCH
+%token	AUTHOR
 %token	<v.string>	STRING
 %token	<v.number>	NUMBER
 %type	<v.number>	boolean portplain
 %type	<v.string>	numberstring
+%type	<v.branch>	branch xbranch branch_list
 
 %%
 
@@ -137,8 +140,30 @@ portplain	: numberstring	{
 				YYERROR;
 			}
 			free($1);
+		}
+		;
+branch		: /* empty */				{ $$ = NULL; }
+		| xbranch			{ $$ = $1; }
+		| '{' optnl branch_list '}'	{ $$ = $3; }
+		;
+xbranch		: STRING {
+			$$ = calloc(1, sizeof(struct node_branch));
+			if ($$ == NULL) {
+				yyerror("calloc");
+				YYERROR;
+			}
+			$$->branch_name = $1;
+			$$->tail = $$;
+		}
+		;
+branch_list	: xbranch optnl			{ $$ = $1; }
+		| branch_list comma xbranch optnl {
+			$1->tail->next = $3;
+			$1->tail = $3;
+			$$ = $1;
 		}
 		;
+
 remoteopts2	: remoteopts2 remoteopts1 nl
 	   	| remoteopts1 optnl
 		;
@@ -174,6 +199,9 @@ remoteopts1	: REPOSITORY STRING {
 		}
 		| PORT portplain {
 			remote->port = $2;
+		}
+		| BRANCH branch {
+			remote->branch = $2;
 		}
 	   	;
 remote		: REMOTE STRING {
@@ -211,6 +239,9 @@ optnl		: '\n' optnl
 		| /* empty */
 		;
 nl		: '\n' optnl
+		;
+comma		: ','
+		| /* empty */
 		;
 %%
 
@@ -254,6 +285,7 @@ lookup(char *s)
 	/* This has to be sorted always. */
 	static const struct keywords keywords[] = {
 		{"author",		AUTHOR},
+		{"branch",		BRANCH},
 		{"mirror-references",	MIRROR_REFERENCES},
 		{"port",		PORT},
 		{"protocol",		PROTOCOL},