From: Martijn van Duren Subject: got: allow clone without symrefs To: gameoftrees@openbsd.org Date: Sat, 14 Jun 2025 01:17:19 +0200 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);