"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Martijn van Duren <openbsd+got@list.imperialat.at>
Subject:
got: allow clone without symrefs
To:
gameoftrees@openbsd.org
Date:
Sat, 14 Jun 2025 01:17:19 +0200

Download raw body.

Thread
Hello all,

Some time ago I got pointed to this repo[0] which doesn't want to clone
without specifying the specific branch. I have no particular usecase
for this repo, but the fact that it couldn't be checked out by default
kept irking me.

After some digging I found out that we rely on symrefs to determine
the default branch. According to the protocol spec[1]:
  Clients MAY use the parameters from this capability to select the
  proper initial branch when cloning a repository.
So it's definitely not a bad thing to do. However, this particular host
doesn't send a symrefs and we're left hanging until you use -l to see
what's available, and then -b to manually specify the branch to check
out.

The diff below adds a workaround for this situation by using the first
refs/heads/ whose id_str matches that of HEAD. It's definitely not
fool proof, but it at least covers this case.

If nothing else, this was a fun exercise.

martijn@

[0] git://git.rodents-montreal.org/liblx
[1] https://git-scm.com/docs/protocol-capabilities/2.22.0

diff /home/martijn/src/got
path + /home/martijn/src/got
commit - e339aba5a8f332c98d0fa01f1d9a5096e89c6045
blob - 736c8e342f847a5c286727292fe961ed4fcac388
file + libexec/got-fetch-pack/got-fetch-pack.c
--- libexec/got-fetch-pack/got-fetch-pack.c
+++ libexec/got-fetch-pack/got-fetch-pack.c
@@ -351,6 +351,7 @@ fetch_pack(int fd, int packfd, uint8_t *pack_sha1,
 	char *id_str = NULL, *default_id_str = NULL, *refname = NULL;
 	char *server_capabilities = NULL, *my_capabilities = NULL;
 	const char *default_branch = NULL;
+	char *free_default_branch = NULL;
 	struct got_pathlist_head symrefs;
 	struct got_pathlist_entry *pe;
 	int sent_my_capabilites = 0, have_sidebands = 0;
@@ -435,6 +436,14 @@ fetch_pack(int fd, int packfd, uint8_t *pack_sha1,
 					default_branch = symref_target;
 					break;
 				}
+				if (default_branch == NULL) {
+					default_id_str = strdup(id_str);
+					if (default_id_str == NULL) {
+						err = got_error_from_errno(
+						    "strdup");
+						goto done;
+					}
+				}
 			}
 			if (default_branch)
 				continue;
@@ -454,6 +463,17 @@ fetch_pack(int fd, int packfd, uint8_t *pack_sha1,
 				goto done;
 			}
 		}
+		/* If no symrefs is given, go for first matching id_str */
+		if (default_branch == NULL && default_id_str &&
+		    strncmp(refname, "refs/heads/", 11) == 0 &&
+		    strcmp(id_str, default_id_str) == 0) {
+			free_default_branch = strdup(refname);
+			if (free_default_branch == NULL) {
+				err = got_error_from_errno("strdup");
+				goto done;
+			}
+			default_branch = free_default_branch;
+		}
 
 		if (list_refs_only || strncmp(refname, "refs/tags/", 10) == 0) {
 			err = fetch_ref(ibuf, have_refs, &have[nref],
@@ -846,6 +866,7 @@ done:
 	free(have);
 	free(want);
 	free(id_str);
+	free(free_default_branch);
 	free(default_id_str);
 	free(refname);
 	free(server_capabilities);