commit - bd56d7e1de5fb58f775afab6d908dbea7a2833de
commit + 118a625d39930284f891ea1285efc17fb3848cae
blob - d9209e2ae1dd1c1aa01e368bc0016cf86830a9e7
blob + bb1825eecded3623bbabcf0541bce55367696327
--- got/got.1
+++ got/got.1
.Xr got.conf 5
or via a work tree, or said branches are not found on the server, a branch
resolved via the remote repository's HEAD reference will be fetched.
+Likewise, if a HEAD reference for the
+.Ar remote-repository
+exists but its target no longer matches the remote HEAD, then
+the new target branch will be fetched.
This default behaviour can be overridden with the
.Fl a
and
blob - b3f92152a92bbdb43288e9569d071a6c9e5895d0
blob + 97e8fcfb43b02a9fb38a2a41964a9a6249b31c2b
--- got/got.c
+++ got/got.c
struct got_fetch_progress_arg fpa;
char *git_url = NULL;
int verbosity = 0, fetch_all_branches = 0, mirror_references = 0;
- int list_refs_only = 0;
+ int bflag = 0, list_refs_only = 0;
int *pack_fds = NULL;
TAILQ_INIT(&refs);
optarg, NULL);
if (error)
return error;
+ bflag = 1;
break;
case 'l':
list_refs_only = 1;
error = got_fetch_pack(&pack_hash, &refs, &symrefs,
GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references,
fetch_all_branches, &wanted_branches, &wanted_refs,
- list_refs_only, verbosity, fetchfd, repo, NULL, 0,
+ list_refs_only, verbosity, fetchfd, repo, NULL, NULL, bflag,
fetch_progress, &fpa);
if (error)
goto done;
const struct got_gotconfig *repo_conf = NULL, *worktree_conf = NULL;
struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
struct got_pathlist_entry *pe;
+ struct got_reflist_head remote_refs;
+ struct got_reflist_entry *re;
struct got_object_id *pack_hash = NULL;
int i, ch, fetchfd = -1, fetchstatus;
pid_t fetchpid = -1;
int verbosity = 0, fetch_all_branches = 0, list_refs_only = 0;
int delete_refs = 0, replace_tags = 0, delete_remote = 0;
int *pack_fds = NULL, have_bflag = 0;
- const char *worktree_branch = NULL;
+ const char *remote_head = NULL, *worktree_branch = NULL;
TAILQ_INIT(&refs);
TAILQ_INIT(&symrefs);
+ TAILQ_INIT(&remote_refs);
TAILQ_INIT(&wanted_branches);
TAILQ_INIT(&wanted_refs);
if (error)
goto done;
- if (worktree && !have_bflag) {
- const char *refname;
+ if (!have_bflag) {
+ /*
+ * If set, get this remote's HEAD ref target so
+ * if it has changed on the server we can fetch it.
+ */
+ error = got_ref_list(&remote_refs, repo, "refs/remotes",
+ got_ref_cmp_by_name, repo);
+ if (error)
+ goto done;
- refname = got_worktree_get_head_ref_name(worktree);
- if (strncmp(refname, "refs/heads/", 11) == 0)
- worktree_branch = refname;
+ TAILQ_FOREACH(re, &remote_refs, entry) {
+ const char *remote_refname, *remote_target;
+ size_t remote_name_len;
+
+ if (!got_ref_is_symbolic(re->ref))
+ continue;
+
+ remote_name_len = strlen(remote->name);
+ remote_refname = got_ref_get_name(re->ref);
+
+ /* we only want refs/remotes/$remote->name/HEAD */
+ if (strncmp(remote_refname + 13, remote->name,
+ remote_name_len) != 0)
+ continue;
+
+ if (strcmp(remote_refname + remote_name_len + 14,
+ GOT_REF_HEAD) != 0)
+ continue;
+
+ /*
+ * Take the name itself because we already
+ * only match with refs/heads/ in fetch_pack().
+ */
+ remote_target = got_ref_get_symref_target(re->ref);
+ remote_head = remote_target + remote_name_len + 14;
+ break;
+ }
+
+ if (worktree) {
+ const char *refname;
+
+ refname = got_worktree_get_head_ref_name(worktree);
+ if (strncmp(refname, "refs/heads/", 11) == 0)
+ worktree_branch = refname;
+ }
}
fpa.last_scaled_size[0] = '\0';
error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name,
remote->mirror_references, fetch_all_branches, &wanted_branches,
&wanted_refs, list_refs_only, verbosity, fetchfd, repo,
- worktree_branch, have_bflag, fetch_progress, &fpa);
+ worktree_branch, remote_head, have_bflag, fetch_progress, &fpa);
if (error)
goto done;
got_pathlist_free(&symrefs, GOT_PATHLIST_FREE_ALL);
got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_NONE);
got_pathlist_free(&wanted_refs, GOT_PATHLIST_FREE_NONE);
+ got_ref_list_free(&remote_refs);
free(id_str);
free(cwd);
free(repo_path);
blob - 5768c9157c81ca12b00f65491c540dd712c37e6a
blob + d14b5f1032910d954b7d663f20e1d8e0b04b216c
--- include/got_fetch.h
+++ include/got_fetch.h
const struct got_error *got_fetch_pack(struct got_object_id **,
struct got_pathlist_head *, struct got_pathlist_head *, const char *,
int, int, struct got_pathlist_head *, struct got_pathlist_head *,
- int, int, int, struct got_repository *, const char *, int,
- got_fetch_progress_cb, void *);
+ int, int, int, struct got_repository *, const char *, const char *,
+ int, got_fetch_progress_cb, void *);
blob - e37808ed2a0bf37771cbf76e39cfa92b60ad43cc
blob + e1ffeced0f65b9b96bebd311728120b80ce7fed9
--- lib/fetch.c
+++ lib/fetch.c
struct got_pathlist_head *wanted_branches,
struct got_pathlist_head *wanted_refs, int list_refs_only, int verbosity,
int fetchfd, struct got_repository *repo, const char *worktree_refname,
- int no_head, got_fetch_progress_cb progress_cb, void *progress_arg)
+ const char *remote_head, int no_head, got_fetch_progress_cb progress_cb,
+ void *progress_arg)
{
size_t i;
int imsg_fetchfds[2], imsg_idxfds[2];
}
err = got_privsep_send_fetch_req(&fetchibuf, nfetchfd, &have_refs,
fetch_all_branches, wanted_branches, wanted_refs,
- list_refs_only, worktree_refname, no_head, verbosity);
+ list_refs_only, worktree_refname, remote_head, no_head, verbosity);
if (err != NULL)
goto done;
nfetchfd = -1;
blob - b8170cb9afee37b2625c705535e43662ca7dd06c
blob + 55cb4225a7ff5f243189735fc4e49c4be4d22e7a
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
int list_refs_only;
int verbosity;
size_t worktree_branch_len;
+ size_t remote_head_len;
size_t n_have_refs;
size_t n_wanted_branches;
size_t n_wanted_refs;
/* Followed by worktree_branch_len bytes of reference name. */
+ /* Followed by remote_head_len bytes of reference name. */
/* Followed by n_have_refs GOT_IMSG_FETCH_HAVE_REF messages. */
/* Followed by n_wanted_branches times GOT_IMSG_FETCH_WANTED_BRANCH. */
/* Followed by n_wanted_refs times GOT_IMSG_FETCH_WANTED_REF. */
int *, int *, struct imsgbuf *ibuf);
const struct got_error *got_privsep_send_fetch_req(struct imsgbuf *, int,
struct got_pathlist_head *, int, struct got_pathlist_head *,
- struct got_pathlist_head *, int, const char *, int, int);
+ struct got_pathlist_head *, int, const char *, const char *, int, int);
const struct got_error *got_privsep_send_fetch_outfd(struct imsgbuf *, int);
const struct got_error *got_privsep_recv_fetch_progress(int *,
struct got_object_id **, char **, struct got_pathlist_head *, char **,
blob - ed227bda3d7a4ce423d882c19ae47793a302c675
blob + a60e0339f8024823ed0d7e275d26f839dbbdb717
--- lib/privsep.c
+++ lib/privsep.c
struct got_pathlist_head *have_refs, int fetch_all_branches,
struct got_pathlist_head *wanted_branches,
struct got_pathlist_head *wanted_refs, int list_refs_only,
- const char *worktree_branch, int no_head, int verbosity)
+ const char *worktree_branch, const char *remote_head,
+ int no_head, int verbosity)
{
const struct got_error *err = NULL;
struct ibuf *wbuf;
- size_t len, worktree_branch_len;
struct got_pathlist_entry *pe;
struct got_imsg_fetch_request fetchreq;
+ size_t remote_head_len, worktree_branch_len, len = sizeof(fetchreq);
if (worktree_branch) {
worktree_branch_len = strlen(worktree_branch);
- len = sizeof(fetchreq) + worktree_branch_len;
- } else
- len = sizeof(fetchreq);
+ len += worktree_branch_len;
+ }
+ if (remote_head) {
+ remote_head_len = strlen(remote_head);
+ len += remote_head_len;
+ }
if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
close(fd);
fetchreq.verbosity = verbosity;
if (worktree_branch != NULL)
fetchreq.worktree_branch_len = worktree_branch_len;
+ if (remote_head != NULL)
+ fetchreq.remote_head_len = remote_head_len;
TAILQ_FOREACH(pe, have_refs, entry)
fetchreq.n_have_refs++;
TAILQ_FOREACH(pe, wanted_branches, entry)
if (imsg_add(wbuf, worktree_branch, worktree_branch_len) == -1)
return got_error_from_errno("imsg_add FETCH_REQUEST");
}
+ if (remote_head) {
+ if (imsg_add(wbuf, remote_head, remote_head_len) == -1)
+ return got_error_from_errno("imsg_add FETCH_REQUEST");
+ }
wbuf->fd = fd;
imsg_close(ibuf, wbuf);
blob - 2a22df95ff37a15b31f41c7c01f263af824ddc15
blob + 83de1f2f31433cea0f0bf579b0a90680763cd8e1
--- libexec/got-fetch-pack/got-fetch-pack.c
+++ libexec/got-fetch-pack/got-fetch-pack.c
struct got_pathlist_head *have_refs, int fetch_all_branches,
struct got_pathlist_head *wanted_branches,
struct got_pathlist_head *wanted_refs, int list_refs_only,
- const char *worktree_branch, int no_head, struct imsgbuf *ibuf)
+ const char *worktree_branch, const char *remote_head,
+ int no_head, struct imsgbuf *ibuf)
{
const struct got_error *err = NULL;
char buf[GOT_PKT_MAX];
if (list_refs_only)
goto done;
- if (!found_branch && !no_head && default_branch && default_id_str &&
+ /*
+ * If -b was not used and either none of the requested branches
+ * (got.conf, worktree) were found or the client already has the
+ * remote HEAD symref but its target changed, fetch remote's HEAD.
+ */
+ if (!no_head && default_branch && default_id_str &&
strncmp(default_branch, "refs/heads/", 11) == 0) {
- err = fetch_ref(ibuf, have_refs, &have[nref],
- &want[nref], default_branch, default_id_str);
- if (err)
- goto done;
- nref++;
- found_branch = 1;
+ int remote_head_changed = 0;
+
+ if (remote_head) {
+ if (strcmp(remote_head, default_branch + 11) != 0)
+ remote_head_changed = 1;
+ }
+
+ if (!found_branch || remote_head_changed) {
+ err = fetch_ref(ibuf, have_refs, &have[nref],
+ &want[nref], default_branch, default_id_str);
+ if (err)
+ goto done;
+ nref++;
+ }
}
/* Abort if we haven't found anything to fetch. */
struct got_imsg_fetch_wanted_branch wbranch;
struct got_imsg_fetch_wanted_ref wref;
size_t datalen, i;
- char *worktree_branch = NULL;
+ char *remote_head = NULL, *worktree_branch = NULL;
#if 0
static int attached;
while (!attached)
fetchfd = imsg.fd;
if (datalen != sizeof(fetch_req) +
- fetch_req.worktree_branch_len) {
+ fetch_req.worktree_branch_len + fetch_req.remote_head_len) {
err = got_error(GOT_ERR_PRIVSEP_LEN);
goto done;
}
worktree_branch = strndup(imsg.data +
sizeof(fetch_req), fetch_req.worktree_branch_len);
if (worktree_branch == NULL) {
+ err = got_error_from_errno("strndup");
+ goto done;
+ }
+ }
+
+ if (fetch_req.remote_head_len != 0) {
+ remote_head = strndup(imsg.data + sizeof(fetch_req) +
+ fetch_req.worktree_branch_len, fetch_req.remote_head_len);
+ if (remote_head == NULL) {
err = got_error_from_errno("strndup");
goto done;
}
err = fetch_pack(fetchfd, packfd, pack_sha1, &have_refs,
fetch_req.fetch_all_branches, &wanted_branches,
&wanted_refs, fetch_req.list_refs_only,
- worktree_branch, fetch_req.no_head, &ibuf);
+ worktree_branch, remote_head, fetch_req.no_head, &ibuf);
done:
free(worktree_branch);
+ free(remote_head);
got_pathlist_free(&have_refs, GOT_PATHLIST_FREE_ALL);
got_pathlist_free(&wanted_branches, GOT_PATHLIST_FREE_PATH);
if (fetchfd != -1 && close(fetchfd) == -1 && err == NULL)