commit - 239821eb715be88de935d7d1b96845b3cb8d324a
commit + 0e4002cadf11b9274c4355850d55bd59bbc20d31
blob - 25d74be5281e94a84e756a0c422e72de0aa32d7e
blob + c42f0af663c423cad213d1b0e5045d338932372c
--- got/got.1
+++ got/got.1
.It Cm im
Short alias for
.Cm import .
-.It Cm clone Oo Fl a Oc Oo Fl b Ar branch Oc Oo Fl l Oc Oo Fl m Oc Oo Fl q Oc Oo Fl v Oc Ar repository-URL Op Ar directory
+.It Cm clone Oo Fl a Oc Oo Fl b Ar branch Oc Oo Fl l Oc Oo Fl m Oc Oo Fl q Oc Oo Fl v Oc Oo Fl R Ar reference Oc Ar repository-URL Op Ar directory
Clone a Git repository at the specified
.Ar repository-URL
into the specified
if applicable.
Multiple -v options increase the verbosity.
The maximum is 3.
+.It Fl R Ar reference
+In addition to the branches and tags that will be fetched, fetch an arbitrary
+.Ar reference
+from the remote repository's
+.Dq refs/
+namespace.
+This option may be specified multiple times to build a list of additional
+references to fetch.
+.Pp
+The references will be mapped into the cloned repository's
+.Dq refs/remotes/
+namespace, unless the
+.Fl m
+option is used to mirror references directly into the cloned repository's
+.Dq refs/
+namespace.
+.Pp
+.Cm got clone
+will refuse to fetch references from the remote repository's
+.Dq refs/remotes/
+or
+.Dq refs/got/
+namespace.
.El
.It Cm cl
Short alias for
if applicable.
Multiple -v options increase the verbosity.
The maximum is 3.
+.It Fl R Ar reference
+In addition to the branches and tags that will be fetched, fetch an arbitrary
+.Ar reference
+from the remote repository's
+.Dq refs/
+namespace.
+This option may be specified multiple times to build a list of additional
+references to fetch.
+.Pp
+Each reference will be mapped into the local repository's
+.Dq refs/remotes/
+namespace, unless the local repository was created as a mirror with
+.Cm got clone -m .
+Once a reference has been fetched, a local branch based on it can be
+created with
+.Cm got branch
+if needed.
+.Pp
+.Cm got fetch
+will refuse to fetch references from the remote repository's
+.Dq refs/remotes/
+or
+.Dq refs/got/
+namespace.
.El
.It Cm fe
Short alias for
blob - 989af2eb06a657a2eef3af8bf6402edafbf95c9c
blob + 4f87cf680b2db1a9e42d32ba9fff5ce4869f50f8
--- got/got.c
+++ got/got.c
usage_clone(void)
{
fprintf(stderr, "usage: %s clone [-a] [-b branch] [-l] [-m] [-q] [-v] "
- "repository-url [directory]\n", getprogname());
+ "[-R reference] repository-url [directory]\n", getprogname());
exit(1);
}
done:
free(id_str);
return err;
+}
+
+static int
+match_wanted_ref(const char *refname, const char *wanted_ref)
+{
+ if (strncmp(refname, "refs/", 5) != 0)
+ return 0;
+ refname += 5;
+
+ /*
+ * Prevent fetching of references that won't make any
+ * sense outside of the remote repository's context.
+ */
+ if (strncmp(refname, "got/", 4) == 0)
+ return 0;
+ if (strncmp(refname, "remotes/", 8) == 0)
+ return 0;
+
+ if (strncmp(wanted_ref, "refs/", 5) == 0)
+ wanted_ref += 5;
+
+ /* Allow prefix match. */
+ if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref)))
+ return 1;
+
+ /* Allow exact match. */
+ return (strcmp(refname, wanted_ref) == 0);
}
+static int
+is_wanted_ref(struct got_pathlist_head *wanted_refs, const char *refname)
+{
+ struct got_pathlist_entry *pe;
+
+ TAILQ_FOREACH(pe, wanted_refs, entry) {
+ if (match_wanted_ref(refname, pe->path))
+ return 1;
+ }
+
+ return 0;
+}
+
static const struct got_error *
+create_wanted_ref(const char *refname, struct got_object_id *id,
+ const char *remote_repo_name, int verbosity, struct got_repository *repo)
+{
+ const struct got_error *err;
+ char *remote_refname;
+
+ if (strncmp("refs/", refname, 5) == 0)
+ refname += 5;
+
+ if (asprintf(&remote_refname, "refs/remotes/%s/%s",
+ remote_repo_name, refname) == -1)
+ return got_error_from_errno("asprintf");
+
+ err = create_ref(remote_refname, id, verbosity, repo);
+ free(remote_refname);
+ return err;
+}
+
+static const struct got_error *
cmd_clone(int argc, char *argv[])
{
const struct got_error *error = NULL;
char *default_destdir = NULL, *id_str = NULL;
const char *repo_path;
struct got_repository *repo = NULL;
- struct got_pathlist_head refs, symrefs, wanted_branches;
+ struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
struct got_pathlist_entry *pe;
struct got_object_id *pack_hash = NULL;
int ch, fetchfd = -1, fetchstatus;
TAILQ_INIT(&refs);
TAILQ_INIT(&symrefs);
TAILQ_INIT(&wanted_branches);
+ TAILQ_INIT(&wanted_refs);
- while ((ch = getopt(argc, argv, "ab:lmvq")) != -1) {
+ while ((ch = getopt(argc, argv, "ab:lmvqR:")) != -1) {
switch (ch) {
case 'a':
fetch_all_branches = 1;
case 'q':
verbosity = -1;
break;
+ case 'R':
+ error = got_pathlist_append(&wanted_refs,
+ optarg, NULL);
+ if (error)
+ return error;
+ break;
default:
usage_clone();
break;
errx(1, "-l and -m options are mutually exclusive");
if (verbosity == -1)
errx(1, "-l and -q options are mutually exclusive");
+ if (!TAILQ_EMPTY(&wanted_refs))
+ errx(1, "-l and -R options are mutually exclusive");
}
uri = argv[0];
fpa.verbosity = verbosity;
error = got_fetch_pack(&pack_hash, &refs, &symrefs,
GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references,
- fetch_all_branches, &wanted_branches, list_refs_only,
- verbosity, fetchfd, repo, fetch_progress, &fpa);
+ fetch_all_branches, &wanted_branches, &wanted_refs,
+ list_refs_only, verbosity, fetchfd, repo,
+ fetch_progress, &fpa);
if (error)
goto done;
const char *refname = pe->path;
struct got_object_id *id = pe->data;
char *remote_refname;
+
+ if (is_wanted_ref(&wanted_refs, refname) &&
+ !mirror_references) {
+ error = create_wanted_ref(refname, id,
+ GOT_FETCH_DEFAULT_REMOTE_NAME,
+ verbosity - 1, repo);
+ if (error)
+ goto done;
+ continue;
+ }
error = create_ref(refname, id, verbosity - 1, repo);
if (error)
}
got_pathlist_free(&symrefs);
got_pathlist_free(&wanted_branches);
+ got_pathlist_free(&wanted_refs);
free(pack_hash);
free(proto);
free(host);
usage_fetch(void)
{
fprintf(stderr, "usage: %s fetch [-a] [-b branch] [-d] [-l] "
- "[-r repository-path] [-t] [-q] [-v] [remote-repository-name]\n",
+ "[-r repository-path] [-t] [-q] [-v] [-R reference] "
+ "[remote-repository-name]\n",
getprogname());
exit(1);
}
got_ref_get_name(re->ref), id_str);
}
}
+
+ return err;
+}
+
+static const struct got_error *
+update_wanted_ref(const char *refname, struct got_object_id *id,
+ const char *remote_repo_name, int verbosity, struct got_repository *repo)
+{
+ const struct got_error *err;
+ char *remote_refname;
+ struct got_reference *ref;
+
+ if (strncmp("refs/", refname, 5) == 0)
+ refname += 5;
+
+ if (asprintf(&remote_refname, "refs/remotes/%s/%s",
+ remote_repo_name, refname) == -1)
+ return got_error_from_errno("asprintf");
+ err = got_ref_open(&ref, repo, remote_refname, 0);
+ if (err) {
+ if (err->code != GOT_ERR_NOT_REF)
+ goto done;
+ err = create_ref(remote_refname, id, verbosity, repo);
+ } else {
+ err = update_ref(ref, id, 0, verbosity, repo);
+ got_ref_close(ref);
+ }
+done:
+ free(remote_refname);
return err;
}
char *id_str = NULL;
struct got_repository *repo = NULL;
struct got_worktree *worktree = NULL;
- struct got_pathlist_head refs, symrefs, wanted_branches;
+ struct got_pathlist_head refs, symrefs, wanted_branches, wanted_refs;
struct got_pathlist_entry *pe;
struct got_object_id *pack_hash = NULL;
int i, ch, fetchfd = -1, fetchstatus;
TAILQ_INIT(&refs);
TAILQ_INIT(&symrefs);
TAILQ_INIT(&wanted_branches);
+ TAILQ_INIT(&wanted_refs);
- while ((ch = getopt(argc, argv, "ab:dlr:tvq")) != -1) {
+ while ((ch = getopt(argc, argv, "ab:dlr:tvqR:")) != -1) {
switch (ch) {
case 'a':
fetch_all_branches = 1;
case 'q':
verbosity = -1;
break;
+ case 'R':
+ error = got_pathlist_append(&wanted_refs,
+ optarg, NULL);
+ if (error)
+ return error;
+ break;
default:
usage_fetch();
break;
fpa.verbosity = verbosity;
error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name,
remote->mirror_references, fetch_all_branches, &wanted_branches,
- list_refs_only, verbosity, fetchfd, repo, fetch_progress, &fpa);
+ &wanted_refs, list_refs_only, verbosity, fetchfd, repo,
+ fetch_progress, &fpa);
if (error)
goto done;
struct got_reference *ref;
char *remote_refname;
+ if (is_wanted_ref(&wanted_refs, refname) &&
+ !remote->mirror_references) {
+ error = update_wanted_ref(refname, id,
+ remote->name, verbosity, repo);
+ if (error)
+ goto done;
+ continue;
+ }
+
if (remote->mirror_references ||
strncmp("refs/tags/", refname, 10) == 0) {
error = got_ref_open(&ref, repo, refname, 0);
}
got_pathlist_free(&symrefs);
got_pathlist_free(&wanted_branches);
+ got_pathlist_free(&wanted_refs);
free(id_str);
free(cwd);
free(repo_path);
blob - 7d8cd87f9386f24c86d96e95cac445f281b1b452
blob + dd38ef5eac3a25d0396293542c1569e376556118
--- include/got_error.h
+++ include/got_error.h
#define GOT_ERR_BAD_PACKET 122
#define GOT_ERR_NO_REMOTE 123
#define GOT_ERR_FETCH_NO_BRANCH 124
+#define GOT_ERR_FETCH_BAD_REF 125
static const struct got_error {
int code;
{ GOT_ERR_BAD_PACKET, "bad packet received" },
{ GOT_ERR_NO_REMOTE, "remote repository not found" },
{ GOT_ERR_FETCH_NO_BRANCH, "could not find any branches to fetch" },
+ { GOT_ERR_FETCH_BAD_REF, "reference cannot be fetched" },
};
/*
blob - 42a3f6350fdf629aaf696b69bd8d27386e5ef3fa
blob + ec4d2dc496a45f2a0804737eeb32ad4991f4c8ba
--- 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 *, int, int, int,
- struct got_repository *, got_fetch_progress_cb, void *);
+ int, int, struct got_pathlist_head *, struct got_pathlist_head *,
+ int, int, int, struct got_repository *, got_fetch_progress_cb, void *);
blob - 4442a20cef8658f67a2edc55456e82264944e572
blob + 9cdf6781c6716b721ebbe42fd37c027823ee6ba8
--- lib/fetch.c
+++ lib/fetch.c
got_fetch_pack(struct got_object_id **pack_hash, struct got_pathlist_head *refs,
struct got_pathlist_head *symrefs, const char *remote_name,
int mirror_references, int fetch_all_branches,
- struct got_pathlist_head *wanted_branches, int list_refs_only,
- int verbosity, int fetchfd, struct got_repository *repo,
+ struct got_pathlist_head *wanted_branches,
+ struct got_pathlist_head *wanted_refs, int list_refs_only, int verbosity,
+ int fetchfd, struct got_repository *repo,
got_fetch_progress_cb progress_cb, void *progress_arg)
{
int imsg_fetchfds[2], imsg_idxfds[2];
char *path;
char *progress = NULL;
+ /*
+ * Prevent fetching of references that won't make any
+ * sense outside of the remote repository's context.
+ */
+ TAILQ_FOREACH(pe, wanted_refs, entry) {
+ const char *refname = pe->path;
+ if (strncmp(refname, "refs/got/", 9) == 0 ||
+ strncmp(refname, "got/", 4) == 0 ||
+ strncmp(refname, "refs/remotes/", 13) == 0 ||
+ strncmp(refname, "remotes/", 8) == 0)
+ return got_error_path(refname, GOT_ERR_FETCH_BAD_REF);
+ }
+
if (!list_refs_only)
repo_path = got_repo_get_path_git_dir(repo);
goto done;
}
err = got_privsep_send_fetch_req(&fetchibuf, nfetchfd, &have_refs,
- fetch_all_branches, wanted_branches, list_refs_only, verbosity);
+ fetch_all_branches, wanted_branches, wanted_refs,
+ list_refs_only, verbosity);
if (err != NULL)
goto done;
nfetchfd = -1;
blob - 8c31f36d79e4b53047ca02d2b0f280b70f84eaa9
blob + dcfb30c7f3aef64701b8fae8369a9a04ded29115
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
GOT_IMSG_FETCH_REQUEST,
GOT_IMSG_FETCH_HAVE_REF,
GOT_IMSG_FETCH_WANTED_BRANCH,
+ GOT_IMSG_FETCH_WANTED_REF,
GOT_IMSG_FETCH_OUTFD,
GOT_IMSG_FETCH_SYMREFS,
GOT_IMSG_FETCH_REF,
/* Structure for GOT_IMSG_FETCH_WANTED_BRANCH data. */
struct got_imsg_fetch_wanted_branch {
+ size_t name_len;
+ /* Followed by name_len data bytes. */
+} __attribute__((__packed__));
+
+/* Structure for GOT_IMSG_FETCH_WANTED_REF data. */
+struct got_imsg_fetch_wanted_ref {
size_t name_len;
/* Followed by name_len data bytes. */
} __attribute__((__packed__));
int verbosity;
size_t n_have_refs;
size_t n_wanted_branches;
+ size_t n_wanted_refs;
/* 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. */
} __attribute__((__packed__));
/* Structures for GOT_IMSG_FETCH_SYMREFS data. */
const struct got_error *got_privsep_recv_index_progress(int *, int *, int *,
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 *, int, int);
+ struct got_pathlist_head *, int, struct got_pathlist_head *,
+ struct got_pathlist_head *, int, int);
const struct got_error *got_privsep_send_fetch_outfd(struct imsgbuf *, int);
const struct got_error *got_privsep_send_fetch_symrefs(struct imsgbuf *,
struct got_pathlist_head *);
blob - 8c47b66e6079d8494ada12b05443c7d960089ae5
blob + 3e7631e45cb6f10d8c034f2706fc258bd7aeea54
--- lib/privsep.c
+++ lib/privsep.c
const struct got_error *
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, int list_refs_only,
- int verbosity)
+ struct got_pathlist_head *wanted_branches,
+ struct got_pathlist_head *wanted_refs, int list_refs_only, int verbosity)
{
const struct got_error *err = NULL;
struct ibuf *wbuf;
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 err;
}
+ TAILQ_FOREACH(pe, wanted_refs, entry) {
+ const char *name = pe->path;
+ size_t name_len = pe->path_len;
+
+ len = sizeof(struct got_imsg_fetch_wanted_ref) + name_len;
+ wbuf = imsg_create(ibuf, GOT_IMSG_FETCH_WANTED_REF, 0, 0,
+ len);
+ if (wbuf == NULL)
+ return got_error_from_errno(
+ "imsg_create FETCH_WANTED_REF");
+
+ /* Keep in sync with struct got_imsg_fetch_wanted_ref! */
+ if (imsg_add(wbuf, &name_len, sizeof(name_len)) == -1) {
+ err = got_error_from_errno(
+ "imsg_add FETCH_WANTED_REF");
+ ibuf_free(wbuf);
+ return err;
+ }
+ if (imsg_add(wbuf, name, name_len) == -1) {
+ err = got_error_from_errno(
+ "imsg_add FETCH_WANTED_REF");
+ ibuf_free(wbuf);
+ return err;
+ }
+
+ wbuf->fd = -1;
+ imsg_close(ibuf, wbuf);
+ err = flush_imsg(ibuf);
+ if (err)
+ return err;
+ }
+
+
return NULL;
}
blob - 70f8e799b2fd3c6d65ef1ffdb6df9a97c48d9579
blob + 8bedceae325de82abd4bbef6715118687872c598
--- libexec/got-fetch-pack/got-fetch-pack.c
+++ libexec/got-fetch-pack/got-fetch-pack.c
wanted_branch += 11;
return (strcmp(branch + 11, wanted_branch) == 0);
+}
+
+static int
+match_wanted_ref(const char *refname, const char *wanted_ref)
+{
+ if (strncmp(refname, "refs/", 5) != 0)
+ return 0;
+ refname += 5;
+
+ /*
+ * Prevent fetching of references that won't make any
+ * sense outside of the remote repository's context.
+ */
+ if (strncmp(refname, "got/", 4) == 0)
+ return 0;
+ if (strncmp(refname, "remotes/", 8) == 0)
+ return 0;
+
+ if (strncmp(wanted_ref, "refs/", 5) == 0)
+ wanted_ref += 5;
+
+ /* Allow prefix match. */
+ if (got_path_is_child(refname, wanted_ref, strlen(wanted_ref)))
+ return 1;
+
+ /* Allow exact match. */
+ return (strcmp(refname, wanted_ref) == 0);
}
static const struct got_error *
static const struct got_error *
fetch_pack(int fd, int packfd, struct got_object_id *packid,
struct got_pathlist_head *have_refs, int fetch_all_branches,
- struct got_pathlist_head *wanted_branches, int list_refs_only,
+ struct got_pathlist_head *wanted_branches,
+ struct got_pathlist_head *wanted_refs, int list_refs_only,
struct imsgbuf *ibuf)
{
const struct got_error *err = NULL;
found_branch = 1;
}
} else if (strncmp(refname, "refs/tags/", 10) != 0) {
- if (!list_refs_only) {
+ 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);
struct imsg imsg;
struct got_pathlist_head have_refs;
struct got_pathlist_head wanted_branches;
+ struct got_pathlist_head wanted_refs;
struct got_pathlist_entry *pe;
struct got_imsg_fetch_request fetch_req;
struct got_imsg_fetch_have_ref href;
struct got_imsg_fetch_wanted_branch wbranch;
+ struct got_imsg_fetch_wanted_ref wref;
size_t datalen;
#if 0
static int attached;
TAILQ_INIT(&have_refs);
TAILQ_INIT(&wanted_branches);
+ TAILQ_INIT(&wanted_refs);
imsg_init(&ibuf, GOT_IMSG_FD_CHILD);
#ifndef PROFILE
imsg_free(&imsg);
}
+ for (i = 0; i < fetch_req.n_wanted_refs; i++) {
+ char *refname;
+
+ if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) {
+ if (err->code == GOT_ERR_PRIVSEP_PIPE)
+ err = NULL;
+ goto done;
+ }
+ if (imsg.hdr.type == GOT_IMSG_STOP)
+ goto done;
+ if (imsg.hdr.type != GOT_IMSG_FETCH_WANTED_REF) {
+ err = got_error(GOT_ERR_PRIVSEP_MSG);
+ goto done;
+ }
+ datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+ if (datalen < sizeof(wref)) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ goto done;
+ }
+ memcpy(&wref, imsg.data, sizeof(wref));
+ if (datalen - sizeof(wref) < wref.name_len) {
+ err = got_error(GOT_ERR_PRIVSEP_LEN);
+ goto done;
+ }
+ refname = malloc(wref.name_len + 1);
+ if (refname == NULL) {
+ err = got_error_from_errno("malloc");
+ goto done;
+ }
+ memcpy(refname, imsg.data + sizeof(wref), wref.name_len);
+ refname[wref.name_len] = '\0';
+
+ err = got_pathlist_append(&wanted_refs, refname, NULL);
+ if (err) {
+ free(refname);
+ goto done;
+ }
+
+ imsg_free(&imsg);
+ }
+
if ((err = got_privsep_recv_imsg(&imsg, &ibuf, 0)) != 0) {
if (err->code == GOT_ERR_PRIVSEP_PIPE)
err = NULL;
err = fetch_pack(fetchfd, packfd, &packid, &have_refs,
fetch_req.fetch_all_branches, &wanted_branches,
- fetch_req.list_refs_only, &ibuf);
+ &wanted_refs, fetch_req.list_refs_only, &ibuf);
done:
TAILQ_FOREACH(pe, &have_refs, entry) {
free((char *)pe->path);
blob - b408166d9ed58cf1a15d4b908ad1a3897a3f44e9
blob + f3a8329ac8336d70b30d8bb5d62f5fa383572eba
--- regress/cmdline/clone.sh
+++ regress/cmdline/clone.sh
fi
test_done "$testroot" "$ret"
}
+
+function test_clone_reference {
+ local testroot=`test_init clone_reference`
+ local testurl=ssh://127.0.0.1/$testroot
+ local commit_id=`git_show_head $testroot/repo`
+ got branch -r $testroot/repo -c $commit_id foo
+ got ref -r $testroot/repo refs/hoo/boo/zoo $commit_id
+ got tag -r $testroot/repo -c $commit_id -m tag "1.0" >/dev/null
+ local tag_id=`got ref -r $testroot/repo -l \
+ | grep "^refs/tags/$tag" | tr -d ' ' | cut -d: -f2`
+
+ got clone -q -R hoo $testurl/repo $testroot/repo-clone
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got clone command failed unexpectedly" >&2
+ 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/hoo/boo/zoo: $commit_id" \
+ >> $testroot/stdout.expected
+ echo "refs/remotes/origin/master: $commit_id" \
+ >> $testroot/stdout.expected
+ echo "refs/tags/1.0: $tag_id" >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout $testroot/stdout.expected
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
+function test_clone_branch_and_reference {
+ local testroot=`test_init clone_reference`
+ local testurl=ssh://127.0.0.1/$testroot
+ local commit_id=`git_show_head $testroot/repo`
+
+ got branch -r $testroot/repo -c $commit_id foo
+ got ref -r $testroot/repo refs/hoo/boo/zoo $commit_id
+ got tag -r $testroot/repo -c $commit_id -m tag "1.0" >/dev/null
+ local tag_id=`got ref -r $testroot/repo -l \
+ | grep "^refs/tags/$tag" | tr -d ' ' | cut -d: -f2`
+
+ got clone -q -R hoo/boo/zoo -b foo $testurl/repo $testroot/repo-clone
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got clone command failed unexpectedly" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ got ref -l -r $testroot/repo-clone > $testroot/stdout
+
+ echo "HEAD: refs/heads/foo" > $testroot/stdout.expected
+ echo "refs/heads/foo: $commit_id" >> $testroot/stdout.expected
+ echo "refs/remotes/origin/foo: $commit_id" \
+ >> $testroot/stdout.expected
+ echo "refs/remotes/origin/hoo/boo/zoo: $commit_id" \
+ >> $testroot/stdout.expected
+ echo "refs/tags/1.0: $tag_id" >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout $testroot/stdout.expected
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
+function test_clone_reference_mirror {
+ local testroot=`test_init clone_reference_mirror`
+ local testurl=ssh://127.0.0.1/$testroot
+ local commit_id=`git_show_head $testroot/repo`
+
+ got branch -r $testroot/repo -c $commit_id foo
+ got ref -r $testroot/repo refs/hoo/boo/zoo $commit_id
+ got tag -r $testroot/repo -c $commit_id -m tag "1.0" >/dev/null
+ local tag_id=`got ref -r $testroot/repo -l \
+ | grep "^refs/tags/$tag" | tr -d ' ' | cut -d: -f2`
+
+ got clone -q -R hoo -m $testurl/repo $testroot/repo-clone
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got clone command failed unexpectedly" >&2
+ 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/hoo/boo/zoo: $commit_id" >> $testroot/stdout.expected
+ echo "refs/tags/1.0: $tag_id" >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout $testroot/stdout.expected
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
run_test test_clone_basic
run_test test_clone_list
run_test test_clone_branch
run_test test_clone_all
run_test test_clone_mirror
run_test test_clone_mirror_all
+run_test test_clone_reference
+run_test test_clone_branch_and_reference
+run_test test_clone_reference_mirror
blob - 374586a754ffabebdadd00bdc20a010dba7fbdd6
blob + ce08ae3c3d285ab16881c6e4ebfe33f5f04117f3
--- regress/cmdline/fetch.sh
+++ regress/cmdline/fetch.sh
fi
test_done "$testroot" "$ret"
}
+
+function test_fetch_reference {
+ local testroot=`test_init fetch_reference`
+ local testurl=ssh://127.0.0.1/$testroot
+ local commit_id=`git_show_head $testroot/repo`
+ got clone -q $testurl/repo $testroot/repo-clone
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got clone command failed unexpectedly" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ got branch -r $testroot/repo -c $commit_id foo
+ got ref -r $testroot/repo refs/hoo/boo/zoo $commit_id
+ got tag -r $testroot/repo -c $commit_id -m tag "1.0" >/dev/null
+ local tag_id=`got ref -r $testroot/repo -l \
+ | grep "^refs/tags/$tag" | tr -d ' ' | cut -d: -f2`
+
+ echo "modified alpha on master" > $testroot/repo/alpha
+ git_commit $testroot/repo -m "modified alpha"
+ local commit_id2=`git_show_head $testroot/repo`
+
+ (cd $testroot/repo && git checkout -q foo)
+ echo "modified alpha on foo" > $testroot/repo/alpha
+ git_commit $testroot/repo -m "modified alpha"
+ local commit_id3=`git_show_head $testroot/repo`
+ (cd $testroot/repo && git checkout -q master)
+
+ got fetch -q -r $testroot/repo-clone -R refs/remotes/origin/main \
+ > $testroot/stdout 2> $testroot/stderr
+ ret="$?"
+ if [ "$ret" == "0" ]; then
+ echo "got fetch command succeeded unexpectedly" >&2
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo -n > $testroot/stdout.expected
+
+ cmp -s $testroot/stdout $testroot/stdout.expected
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ echo "got: refs/remotes/origin/main: reference cannot be fetched" \
+ > $testroot/stderr.expected
+
+ cmp -s $testroot/stderr $testroot/stderr.expected
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stderr.expected $testroot/stderr
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ got fetch -q -r $testroot/repo-clone -R refs/hoo
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ echo "got fetch command failed unexpectedly" >&2
+ 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/hoo/boo/zoo: $commit_id" \
+ >> $testroot/stdout.expected
+ echo "refs/remotes/origin/master: $commit_id2" \
+ >> $testroot/stdout.expected
+ echo "refs/tags/1.0: $tag_id" >> $testroot/stdout.expected
+
+ cmp -s $testroot/stdout $testroot/stdout.expected
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+
+}
+
run_test test_fetch_basic
run_test test_fetch_list
run_test test_fetch_branch
run_test test_fetch_empty_packfile
run_test test_fetch_delete_branch
run_test test_fetch_update_tag
+run_test test_fetch_reference