commit - c9003c52fc7f70dd988402560adcd22709e74800
commit + 188f8dcf2c1c15bf37859e3b587bc6331fd5a097
blob - a32137a402ce476d4300983fe5e9e17d680c8ac0
blob + 83d6a791c83d96ed0e79da912f70428804dfcb3a
--- got/got.c
+++ got/got.c
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,
+ list_refs_only, verbosity, fetchfd, repo, NULL,
fetch_progress, &fpa);
if (error)
goto done;
struct got_fetch_progress_arg fpa;
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;
+ int *pack_fds = NULL, have_bflag = 0;
TAILQ_INIT(&refs);
TAILQ_INIT(&symrefs);
optarg, NULL);
if (error)
return error;
+ have_bflag = 1;
break;
case 'd':
delete_refs = 1;
if (error)
goto done;
}
- if (worktree) {
- error = got_pathlist_append(&wanted_branches,
- got_worktree_get_head_ref_name(worktree), NULL);
- if (error)
- goto done;
- }
}
if (TAILQ_EMPTY(&wanted_refs)) {
for (i = 0; i < remote->nfetch_refs; i++) {
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 != NULL && !have_bflag) ?
+ got_worktree_get_head_ref_name(worktree) : NULL,
fetch_progress, &fpa);
if (error)
goto done;
blob - 49f9fd5da6c527fcc00a29827b61df267135112e
blob + 5703d1fbe97e2c2bfcb5c6c2095c9653f5ee5e6e
--- 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 *, got_fetch_progress_cb, void *);
+ int, int, int, struct got_repository *, const char *,
+ got_fetch_progress_cb, void *);
blob - a006844341e6b3ee524360e3929fe3eee0536090
blob + bfa126b8fabcca280af94961030dcae5aae3e6e6
--- lib/fetch.c
+++ lib/fetch.c
int mirror_references, int fetch_all_branches,
struct got_pathlist_head *wanted_branches,
struct got_pathlist_head *wanted_refs, int list_refs_only, int verbosity,
- int fetchfd, struct got_repository *repo,
+ int fetchfd, struct got_repository *repo, const char *worktree_refname,
got_fetch_progress_cb progress_cb, void *progress_arg)
{
size_t i;
}
err = got_privsep_send_fetch_req(&fetchibuf, nfetchfd, &have_refs,
fetch_all_branches, wanted_branches, wanted_refs,
- list_refs_only, verbosity);
+ list_refs_only, worktree_refname, verbosity);
if (err != NULL)
goto done;
nfetchfd = -1;
blob - 076cab5adad635b8e7ea46af68a14510dced4da4
blob + 09e7cb7ce6e9cf826f667d69280ad2dab4b4d161
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
int fetch_all_branches;
int list_refs_only;
int verbosity;
+ size_t worktree_branch_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 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, int);
+ struct got_pathlist_head *, int, const char *, 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 - ddb1e595d753eddc725ce0bbb056d1dc8236fc07
blob + d99805a6e345d6d142e6a571b2f787068b19ef76
--- lib/privsep.c
+++ lib/privsep.c
got_privsep_send_fetch_req(struct imsgbuf *ibuf, int fd,
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, int verbosity)
+ struct got_pathlist_head *wanted_refs, int list_refs_only,
+ const char *worktree_branch, int verbosity)
{
const struct got_error *err = NULL;
struct ibuf *wbuf;
struct got_pathlist_entry *pe;
struct got_imsg_fetch_request fetchreq;
+ if (worktree_branch)
+ len = sizeof(fetchreq) + strlen(worktree_branch);
+ else
+ len = sizeof(fetchreq);
+
+ if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
+ close(fd);
+ return got_error(GOT_ERR_NO_SPACE);
+ }
+
+ wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_REQUEST, 0, 0, len);
+ if (wbuf == NULL)
+ return got_error_from_errno("imsg_create FETCH_HAVE_REF");
+
memset(&fetchreq, 0, sizeof(fetchreq));
fetchreq.fetch_all_branches = fetch_all_branches;
fetchreq.list_refs_only = list_refs_only;
fetchreq.verbosity = verbosity;
+ if (worktree_branch != NULL)
+ fetchreq.worktree_branch_len = strlen(worktree_branch);
TAILQ_FOREACH(pe, have_refs, entry)
fetchreq.n_have_refs++;
TAILQ_FOREACH(pe, wanted_branches, entry)
fetchreq.n_wanted_branches++;
TAILQ_FOREACH(pe, wanted_refs, entry)
fetchreq.n_wanted_refs++;
- len = sizeof(struct got_imsg_fetch_request);
- if (len >= MAX_IMSGSIZE - IMSG_HEADER_SIZE) {
- close(fd);
- return got_error(GOT_ERR_NO_SPACE);
+ if (imsg_add(wbuf, &fetchreq, sizeof(fetchreq)) == -1)
+ return got_error_from_errno("imsg_add FETCH_REQUEST");
+ if (worktree_branch) {
+ if (imsg_add(wbuf, worktree_branch,
+ strlen(worktree_branch))== -1)
+ return got_error_from_errno("imsg_add FETCH_REQUEST");
}
-
- if (imsg_compose(ibuf, GOT_IMSG_FETCH_REQUEST, 0, 0, fd,
- &fetchreq, sizeof(fetchreq)) == -1)
- return got_error_from_errno(
- "imsg_compose FETCH_SERVER_PROGRESS");
+ wbuf->fd = fd;
+ imsg_close(ibuf, wbuf);
err = flush_imsg(ibuf);
if (err) {
blob - 77ba914fb971f5e412b57bd1633bda6ee0e1f26d
blob + 32778499296b895c8f8a0bd7f201ca9a637c6f87
--- libexec/got-fetch-pack/got-fetch-pack.c
+++ libexec/got-fetch-pack/got-fetch-pack.c
static void
match_remote_ref(struct got_pathlist_head *have_refs,
- struct got_object_id *my_id, char *refname)
+ struct got_object_id *my_id, const char *refname)
{
struct got_pathlist_entry *pe;
wbuf->fd = -1;
imsg_close(ibuf, wbuf);
return got_privsep_flush_imsg(ibuf);
+}
+
+static const struct got_error *
+fetch_ref(struct imsgbuf *ibuf, struct got_pathlist_head *have_refs,
+ struct got_object_id *have, struct got_object_id *want,
+ const char *refname, const char *id_str)
+{
+ const struct got_error *err;
+ char *theirs = NULL, *mine = NULL;
+
+ if (!got_parse_sha1_digest(want->sha1, id_str)) {
+ err = got_error(GOT_ERR_BAD_OBJ_ID_STR);
+ goto done;
+ }
+
+ match_remote_ref(have_refs, have, refname);
+ err = send_fetch_ref(ibuf, want, refname);
+ if (err)
+ goto done;
+
+ if (chattygot)
+ fprintf(stderr, "%s: %s will be fetched\n",
+ getprogname(), refname);
+ if (chattygot > 1) {
+ err = got_object_id_str(&theirs, want);
+ if (err)
+ goto done;
+ err = got_object_id_str(&mine, have);
+ if (err)
+ goto done;
+ fprintf(stderr, "%s: remote: %s\n%s: local: %s\n",
+ getprogname(), theirs, getprogname(), mine);
+ }
+done:
+ free(theirs);
+ free(mine);
+ return err;
}
static const struct got_error *
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,
- struct imsgbuf *ibuf)
+ const char *worktree_branch, struct imsgbuf *ibuf)
{
const struct got_error *err = NULL;
char buf[GOT_PKT_MAX];
int is_firstpkt = 1, nref = 0, refsz = 16;
int i, n, nwant = 0, nhave = 0, acked = 0;
off_t packsz = 0, last_reported_packsz = 0;
- char *id_str = NULL, *refname = NULL;
+ char *id_str = NULL, *default_id_str = NULL, *refname = NULL;
char *server_capabilities = NULL, *my_capabilities = NULL;
const char *default_branch = NULL;
struct got_pathlist_head symrefs;
&server_capabilities, buf, n);
if (err)
goto done;
+
+ if (refsz == nref + 1) {
+ refsz *= 2;
+ have = reallocarray(have, refsz, sizeof(have[0]));
+ if (have == NULL) {
+ err = got_error_from_errno("reallocarray");
+ goto done;
+ }
+ want = reallocarray(want, refsz, sizeof(want[0]));
+ if (want == NULL) {
+ err = got_error_from_errno("reallocarray");
+ goto done;
+ }
+ }
+
if (is_firstpkt) {
if (chattygot && server_capabilities[0] != '\0')
fprintf(stderr, "%s: server capabilities: %s\n",
}
continue;
}
-
- if (strncmp(refname, "refs/heads/", 11) == 0) {
- if (fetch_all_branches || list_refs_only) {
- found_branch = 1;
- } else if (!TAILQ_EMPTY(wanted_branches)) {
- TAILQ_FOREACH(pe, wanted_branches, entry) {
- if (match_branch(refname, pe->path))
- break;
- }
- if (pe == NULL) {
- if (chattygot) {
- fprintf(stderr,
- "%s: ignoring %s\n",
- getprogname(), refname);
- }
- continue;
- }
- found_branch = 1;
- } else if (default_branch != NULL) {
- if (!match_branch(refname, default_branch)) {
- if (chattygot) {
- fprintf(stderr,
- "%s: ignoring %s\n",
- getprogname(), refname);
- }
- continue;
- }
- found_branch = 1;
- }
- } else if (strncmp(refname, "refs/tags/", 10) != 0) {
- if (!TAILQ_EMPTY(wanted_refs)) {
- TAILQ_FOREACH(pe, wanted_refs, entry) {
- if (match_wanted_ref(refname, pe->path))
- break;
- }
- if (pe == NULL) {
- if (chattygot) {
- fprintf(stderr,
- "%s: ignoring %s\n",
- getprogname(), refname);
- }
- continue;
- }
- found_branch = 1;
- } else if (!list_refs_only) {
- if (chattygot) {
- fprintf(stderr, "%s: ignoring %s\n",
- getprogname(), refname);
- }
- continue;
- }
- }
-
- if (refsz == nref + 1) {
- refsz *= 2;
- have = reallocarray(have, refsz, sizeof(have[0]));
- if (have == NULL) {
- err = got_error_from_errno("reallocarray");
- goto done;
- }
- want = reallocarray(want, refsz, sizeof(want[0]));
- if (want == NULL) {
- err = got_error_from_errno("reallocarray");
+ if (default_branch && default_id_str == NULL &&
+ strcmp(refname, default_branch) == 0) {
+ default_id_str = strdup(id_str);
+ if (default_id_str == NULL) {
+ err = got_error_from_errno("strdup");
goto done;
}
}
- if (!got_parse_sha1_digest(want[nref].sha1, id_str)) {
- err = got_error(GOT_ERR_BAD_OBJ_ID_STR);
- goto done;
- }
- match_remote_ref(have_refs, &have[nref], refname);
- err = send_fetch_ref(ibuf, &want[nref], refname);
- if (err)
- goto done;
- if (chattygot)
- fprintf(stderr, "%s: %s will be fetched\n",
- getprogname(), refname);
- if (chattygot > 1) {
- char *theirs, *mine;
- err = got_object_id_str(&theirs, &want[nref]);
+ if (list_refs_only || strncmp(refname, "refs/tags/", 10) == 0) {
+ err = fetch_ref(ibuf, have_refs, &have[nref],
+ &want[nref], refname, id_str);
if (err)
goto done;
- err = got_object_id_str(&mine, &have[nref]);
- if (err) {
- free(theirs);
- goto done;
+ nref++;
+ } else if (strncmp(refname, "refs/heads/", 11) == 0) {
+ if (fetch_all_branches) {
+ err = fetch_ref(ibuf, have_refs, &have[nref],
+ &want[nref], refname, id_str);
+ if (err)
+ goto done;
+ nref++;
+ found_branch = 1;
+ continue;
}
- fprintf(stderr, "%s: remote: %s\n%s: local: %s\n",
- getprogname(), theirs, getprogname(), mine);
- free(theirs);
- free(mine);
+ TAILQ_FOREACH(pe, wanted_branches, entry) {
+ if (match_branch(refname, pe->path))
+ break;
+ }
+ if (pe != NULL || (worktree_branch != NULL &&
+ match_branch(refname, worktree_branch))) {
+ err = fetch_ref(ibuf, have_refs, &have[nref],
+ &want[nref], refname, id_str);
+ if (err)
+ goto done;
+ nref++;
+ found_branch = 1;
+ } else if (chattygot) {
+ fprintf(stderr, "%s: ignoring %s\n",
+ getprogname(), refname);
+ }
+ } else {
+ TAILQ_FOREACH(pe, wanted_refs, entry) {
+ if (match_wanted_ref(refname, pe->path))
+ break;
+ }
+ if (pe != NULL) {
+ err = fetch_ref(ibuf, have_refs, &have[nref],
+ &want[nref], refname, id_str);
+ if (err)
+ goto done;
+ nref++;
+ } else if (chattygot) {
+ fprintf(stderr, "%s: ignoring %s\n",
+ getprogname(), refname);
+ }
}
- nref++;
}
if (list_refs_only)
goto done;
- /* Abort if we haven't found any branch to fetch. */
- if (!found_branch) {
+ if (!found_branch && 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;
+ }
+
+ /* Abort if we haven't found anything to fetch. */
+ if (nref == 0) {
err = got_error(GOT_ERR_FETCH_NO_BRANCH);
goto done;
}
free(have);
free(want);
free(id_str);
+ free(default_id_str);
free(refname);
free(server_capabilities);
return err;
struct got_imsg_fetch_wanted_branch wbranch;
struct got_imsg_fetch_wanted_ref wref;
size_t datalen, i;
+ char *worktree_branch = NULL;
#if 0
static int attached;
while (!attached)
}
memcpy(&fetch_req, imsg.data, sizeof(fetch_req));
fetchfd = imsg.fd;
+
+ if (datalen != sizeof(fetch_req) +
+ fetch_req.worktree_branch_len) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ goto done;
+ }
+
+ if (fetch_req.worktree_branch_len != 0) {
+ 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;
+ }
+ }
+
imsg_free(&imsg);
if (fetch_req.verbosity > 0)
err = fetch_pack(fetchfd, packfd, pack_sha1, &have_refs,
fetch_req.fetch_all_branches, &wanted_branches,
- &wanted_refs, fetch_req.list_refs_only, &ibuf);
+ &wanted_refs, fetch_req.list_refs_only,
+ worktree_branch, &ibuf);
done:
+ free(worktree_branch);
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)
blob - 0f381607476a2ed62e00ff9cb319557a26e8d633
blob + 26346effc18d13d5e986f7072e63b5d9c885450f
--- regress/cmdline/fetch.sh
+++ regress/cmdline/fetch.sh
# foo is now the default HEAD branch in $testroot/repo
# but got.conf still says to fetch "master"
+ got fetch -q -r $testroot/repo-clone > $testroot/stdout
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ echo "got fetch command failed unexpectedly" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo -n > $testroot/stdout.expected
+
+ cmp -s $testroot/stdout $testroot/stdout.expected
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ got ref -l -r $testroot/repo-clone > $testroot/stdout
+
+ echo "HEAD: refs/heads/master" > $testroot/stdout.expected
+ echo "refs/heads/master: $commit_id" >> $testroot/stdout.expected
+ echo "refs/remotes/origin/HEAD: refs/remotes/origin/master" \
+ >> $testroot/stdout.expected
+ echo "refs/remotes/origin/master: $commit_id2" \
+ >> $testroot/stdout.expected
+ # refs/hoo/boo/zoo is missing because it is outside of refs/heads
+ echo "refs/tags/1.0: $tag_id" >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout $testroot/stdout.expected
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # fetch branch foo via command-line switch
got fetch -q -r $testroot/repo-clone -b foo > $testroot/stdout
ret=$?
if [ $ret -ne 0 ]; then
echo "refs/remotes/origin/HEAD: refs/remotes/origin/foo" \
>> $testroot/stdout.expected
echo "refs/remotes/origin/foo: $commit_id3" >> $testroot/stdout.expected
- # refs/remotes/origin/master is umodified because it wasn't fetched
- echo "refs/remotes/origin/master: $commit_id" \
+ echo "refs/remotes/origin/master: $commit_id2" \
>> $testroot/stdout.expected
# refs/hoo/boo/zoo is missing because it is outside of refs/heads
echo "refs/tags/1.0: $tag_id" >> $testroot/stdout.expected
ret=$?
if [ $ret -ne 0 ]; then
diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
fi
+
+ # remove default branch information from got.conf
+ sed -i -e "/branch {/d" $testroot/repo-clone/got.conf
+
+ # make another change on 'foo' and fetch it without got.conf
+ (cd $testroot/repo && git checkout -q foo)
+ echo "modified beta on foo agan" > $testroot/repo/beta
+ git_commit $testroot/repo -m "modified beta"
+ local commit_id5=`git_show_head $testroot/repo`
+ (cd $testroot/repo && git checkout -q master)
+
+ # fetch new commits on branch 'foo', implicitly obtaining the
+ # branch name from a work tree
+ (cd $testroot/wt && got fetch -q > $testroot/stdout)
+
+ echo -n > $testroot/stdout.expected
+
+ cmp -s $testroot/stdout $testroot/stdout.expected
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ wt_uuid=`(cd $testroot/wt && got info | grep 'UUID:' | \
+ cut -d ':' -f 2 | tr -d ' ')`
+
+ got ref -l -r $testroot/repo-clone > $testroot/stdout
+
+ echo "HEAD: refs/heads/master" > $testroot/stdout.expected
+ echo "refs/got/worktree/base-$wt_uuid: $commit_id3" \
+ >> $testroot/stdout.expected
+ echo "refs/heads/foo: $commit_id3" >> $testroot/stdout.expected
+ echo "refs/heads/master: $commit_id" >> $testroot/stdout.expected
+ echo "refs/remotes/origin/HEAD: refs/remotes/origin/master" \
+ >> $testroot/stdout.expected
+ echo "refs/remotes/origin/foo: $commit_id5" >> $testroot/stdout.expected
+ echo "refs/remotes/origin/master: $commit_id2" \
+ >> $testroot/stdout.expected
+ # refs/hoo/boo/zoo is missing because it is outside of refs/heads
+ echo "refs/tags/1.0: $tag_id" >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout $testroot/stdout.expected
+ ret=$?
+ if [ $ret -ne 0 ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
test_done "$testroot" "$ret"
}