commit - 1f03b8da6be221784414918f66390ccb0eb67908
commit + 41b0de1256a7a8a9ed3d4c0d66809ebfcbf1a58d
blob - 869f13d9c5e81da78233fd60e855d60bb5c769be
blob + 9b734106ce0c02a0c08f7dceeb7d5ac834988511
--- 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 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 Ar repository-URL Op Ar directory
Clone a Git repository at the specified
.Ar repository-URL
into the specified
Cannot be used together with the
.Fl a
option.
+.It Fl l
+List branches and tags available for cloning from the remote repository
+and exit immediately.
+Cannot be used together with any of the other options except
+.Fl v .
.It Fl m
Create the cloned repository as a mirror of the original repository.
This is useful if the cloned repository will not be used to store
.It Cm cl
Short alias for
.Cm clone .
-.It Cm fetch Oo Fl a Oc Oo Fl b Ar branch Oc Oo Fl r Ar repository-path Oc Oo Fl q Oc Oo Fl v Oc Op Ar remote-repository
+.It Cm fetch Oo Fl a Oc Oo Fl b Ar branch Oc Oo Fl l Oc Oo Fl r Ar repository-path Oc Oo Fl q Oc Oo Fl v Oc Op Ar remote-repository
Fetch new changes from a remote repository.
If no
.Ar remote-repository
Cannot be used together with the
.Fl a
option.
+.It Fl l
+List branches and tags available for fetching from the remote repository
+and exit immediately.
+Cannot be used together with any of the other options except
+.Fl v
+and
+.Fl r .
.It Fl r Ar repository-path
Use the repository at the specified path.
If not specified, assume the repository is located at or above the current
blob - d0e6d7f2e6b486b9103d7efb0dd24322773ab138
blob + a1aea8a8405c27c3618d0bb30e4faaf8d51d9c7a
--- got/got.c
+++ got/got.c
}
static const struct got_error *
+list_remote_refs(struct got_pathlist_head *symrefs,
+ struct got_pathlist_head *refs)
+{
+ const struct got_error *err;
+ struct got_pathlist_entry *pe;
+
+ TAILQ_FOREACH(pe, symrefs, entry) {
+ const char *refname = pe->path;
+ const char *targetref = pe->data;
+
+ printf("%s: %s\n", refname, targetref);
+ }
+
+ TAILQ_FOREACH(pe, refs, entry) {
+ const char *refname = pe->path;
+ struct got_object_id *id = pe->data;
+ char *id_str;
+
+ err = got_object_id_str(&id_str, id);
+ if (err)
+ return err;
+ printf("%s: %s\n", refname, id_str);
+ free(id_str);
+ }
+
+ return NULL;
+}
+
+static const struct got_error *
cmd_clone(int argc, char *argv[])
{
const struct got_error *error = NULL;
FILE *gitconfig_file = NULL;
ssize_t n;
int verbosity = 0, fetch_all_branches = 0, mirror_references = 0;
+ int list_refs_only = 0;
struct got_reference *head_symref = NULL;
TAILQ_INIT(&refs);
TAILQ_INIT(&symrefs);
TAILQ_INIT(&wanted_branches);
- while ((ch = getopt(argc, argv, "ab:mvq")) != -1) {
+ while ((ch = getopt(argc, argv, "ab:lmvq")) != -1) {
switch (ch) {
case 'a':
fetch_all_branches = 1;
if (error)
return error;
break;
+ case 'l':
+ list_refs_only = 1;
+ break;
case 'm':
mirror_references = 1;
break;
argv += optind;
if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches))
- errx(1, "-a and -b options are mutually exclusive\n");
+ errx(1, "-a and -b options are mutually exclusive");
+ if (list_refs_only) {
+ if (!TAILQ_EMPTY(&wanted_branches))
+ errx(1, "-l and -b options are mutually exclusive");
+ if (fetch_all_branches)
+ errx(1, "-l and -a options are mutually exclusive");
+ if (mirror_references)
+ errx(1, "-l and -m options are mutually exclusive");
+ if (verbosity == -1)
+ errx(1, "-l and -q options are mutually exclusive");
+ }
uri = argv[0];
} else
repo_path = dirname;
- error = got_path_mkdir(repo_path);
- if (error)
- goto done;
+ if (!list_refs_only) {
+ error = got_path_mkdir(repo_path);
+ if (error)
+ goto done;
- error = got_repo_init(repo_path);
- if (error)
- goto done;
+ error = got_repo_init(repo_path);
+ if (error)
+ goto done;
+ error = got_repo_open(&repo, repo_path, NULL);
+ if (error)
+ goto done;
+ }
- error = got_repo_open(&repo, repo_path, NULL);
- if (error)
- goto done;
-
if (strcmp(proto, "git+ssh") == 0 || strcmp(proto, "ssh") == 0) {
if (unveil(GOT_FETCH_PATH_SSH, "x") != 0) {
error = got_error_from_errno2("unveil",
goto done;
}
}
- error = apply_unveil(got_repo_get_path(repo), 0, NULL);
+ error = apply_unveil(repo ? got_repo_get_path(repo) : NULL, 0, NULL);
if (error)
goto done;
fpa.verbosity = verbosity;
error = got_fetch_pack(&pack_hash, &refs, &symrefs,
GOT_FETCH_DEFAULT_REMOTE_NAME, mirror_references,
- fetch_all_branches, &wanted_branches, fetchfd,
- repo, fetch_progress, &fpa);
+ fetch_all_branches, &wanted_branches, list_refs_only,
+ fetchfd, repo, fetch_progress, &fpa);
if (error)
goto done;
+ if (list_refs_only) {
+ error = list_remote_refs(&symrefs, &refs);
+ goto done;
+ }
+
error = got_object_id_str(&id_str, pack_hash);
if (error)
goto done;
struct got_object_id *pack_hash = NULL;
int i, ch, fetchfd = -1;
struct got_fetch_progress_arg fpa;
- int verbosity = 0, fetch_all_branches = 0;
+ int verbosity = 0, fetch_all_branches = 0, list_refs_only = 0;
TAILQ_INIT(&refs);
TAILQ_INIT(&symrefs);
TAILQ_INIT(&wanted_branches);
- while ((ch = getopt(argc, argv, "ab:r:vq")) != -1) {
+ while ((ch = getopt(argc, argv, "ab:lr:vq")) != -1) {
switch (ch) {
case 'a':
fetch_all_branches = 1;
optarg, NULL);
if (error)
return error;
+ break;
+ case 'l':
+ list_refs_only = 1;
break;
case 'r':
repo_path = realpath(optarg, NULL);
argv += optind;
if (fetch_all_branches && !TAILQ_EMPTY(&wanted_branches))
- errx(1, "-a and -b options are mutually exclusive\n");
+ errx(1, "-a and -b options are mutually exclusive");
+ if (list_refs_only) {
+ if (!TAILQ_EMPTY(&wanted_branches))
+ errx(1, "-l and -b options are mutually exclusive");
+ if (fetch_all_branches)
+ errx(1, "-l and -a options are mutually exclusive");
+ if (verbosity == -1)
+ errx(1, "-l and -q options are mutually exclusive");
+ }
if (argc == 0)
remote_name = GOT_FETCH_DEFAULT_REMOTE_NAME;
fpa.verbosity = verbosity;
error = got_fetch_pack(&pack_hash, &refs, &symrefs, remote->name,
remote->mirror_references, fetch_all_branches, &wanted_branches,
- fetchfd, repo, fetch_progress, &fpa);
+ list_refs_only, fetchfd, repo, fetch_progress, &fpa);
if (error)
goto done;
+ if (list_refs_only) {
+ error = list_remote_refs(&symrefs, &refs);
+ goto done;
+ }
+
if (pack_hash == NULL) {
if (verbosity >= 0)
printf("Already up-to-date\n");
blob - a7b9590dcef74fceec8004075319634cc5f5e462
blob + 9e26b62a0b5d1a4848d98980cd9a7b5bc73fd1aa
--- 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, struct got_repository *,
+ int, int, struct got_pathlist_head *, int, int, struct got_repository *,
got_fetch_progress_cb, void *);
blob - d9e55b8853c1065604fa45460938e09c2444b97b
blob + fcd9bb07bd25aa7e1ed09ad450f14bebbaf623b4
--- 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 fetchfd,
- struct got_repository *repo,
+ struct got_pathlist_head *wanted_branches, int list_refs_only,
+ int fetchfd, struct got_repository *repo,
got_fetch_progress_cb progress_cb, void *progress_arg)
{
int imsg_fetchfds[2], imsg_idxfds[2];
pid_t fetchpid, idxpid;
char *tmppackpath = NULL, *tmpidxpath = NULL;
char *packpath = NULL, *idxpath = NULL, *id_str = NULL;
- const char *repo_path = got_repo_get_path_git_dir(repo);
+ const char *repo_path = NULL;
struct got_pathlist_head have_refs;
struct got_pathlist_entry *pe;
struct got_reflist_head my_refs;
size_t ref_prefixlen = 0;
char *path;
char *progress = NULL;
+
+ if (!list_refs_only)
+ repo_path = got_repo_get_path_git_dir(repo);
*pack_hash = NULL;
for (i = 0; i < nitems(tmpfds); i++)
ref_prefixlen = strlen(ref_prefix);
}
- err = got_ref_list(&my_refs, repo, NULL, got_ref_cmp_by_name, NULL);
- if (err)
- goto done;
+ if (!list_refs_only) {
+ err = got_ref_list(&my_refs, repo, NULL,
+ got_ref_cmp_by_name, NULL);
+ if (err)
+ goto done;
+ }
SIMPLEQ_FOREACH(re, &my_refs, entry) {
struct got_object_id *id;
}
}
- if (asprintf(&path, "%s/%s/fetching.pack",
- repo_path, GOT_OBJECTS_PACK_DIR) == -1) {
- err = got_error_from_errno("asprintf");
- goto done;
+ if (list_refs_only) {
+ packfd = got_opentempfd();
+ if (packfd == -1) {
+ err = got_error_from_errno("got_opentempfd");
+ goto done;
+ }
+ } else {
+ if (asprintf(&path, "%s/%s/fetching.pack",
+ repo_path, GOT_OBJECTS_PACK_DIR) == -1) {
+ err = got_error_from_errno("asprintf");
+ goto done;
+ }
+ err = got_opentemp_named_fd(&tmppackpath, &packfd, path);
+ free(path);
+ if (err)
+ goto done;
}
- err = got_opentemp_named_fd(&tmppackpath, &packfd, path);
- free(path);
- if (err)
- goto done;
npackfd = dup(packfd);
if (npackfd == -1) {
err = got_error_from_errno("dup");
goto done;
}
- if (asprintf(&path, "%s/%s/fetching.idx",
- repo_path, GOT_OBJECTS_PACK_DIR) == -1) {
- err = got_error_from_errno("asprintf");
- goto done;
+ if (list_refs_only) {
+ idxfd = got_opentempfd();
+ if (idxfd == -1) {
+ err = got_error_from_errno("got_opentempfd");
+ goto done;
+ }
+ } else {
+ if (asprintf(&path, "%s/%s/fetching.idx",
+ repo_path, GOT_OBJECTS_PACK_DIR) == -1) {
+ err = got_error_from_errno("asprintf");
+ goto done;
+ }
+ err = got_opentemp_named_fd(&tmpidxpath, &idxfd, path);
+ free(path);
+ if (err)
+ goto done;
}
- err = got_opentemp_named_fd(&tmpidxpath, &idxfd, path);
- free(path);
- if (err)
- goto done;
nidxfd = dup(idxfd);
if (nidxfd == -1) {
err = got_error_from_errno("dup");
goto done;
}
err = got_privsep_send_fetch_req(&fetchibuf, nfetchfd, &have_refs,
- fetch_all_branches, wanted_branches);
+ fetch_all_branches, wanted_branches, list_refs_only);
if (err != NULL)
goto done;
nfetchfd = -1;
else
free(id);
} else if (refname && id) {
- err = got_pathlist_append(refs, refname, id);
+ err = got_pathlist_insert(NULL, refs, refname, id);
if (err)
goto done;
} else if (server_progress) {
blob - ca92bcd3660a9b973c8c555f1cbb36a1c0fede5b
blob + b542cec86ba90e8bd23eabe37271fc2faf08ce72
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
/* Structure for GOT_IMSG_FETCH_REQUEST data. */
struct got_imsg_fetch_request {
int fetch_all_branches;
+ int list_refs_only;
size_t n_have_refs;
size_t n_wanted_branches;
/* Followed by n_have_refs GOT_IMSG_FETCH_HAVE_REF messages. */
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 *);
+ struct got_pathlist_head *, int, struct got_pathlist_head *, 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 - 805dd3e8bcf919be36494e99aa5351e30d121d66
blob + 2baa585778c31396c55ca867abadd1baae6a09a8
--- 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)
+ struct got_pathlist_head *wanted_branches, int list_refs_only)
{
const struct got_error *err = NULL;
struct ibuf *wbuf;
memset(&fetchreq, 0, sizeof(fetchreq));
fetchreq.fetch_all_branches = fetch_all_branches;
+ fetchreq.list_refs_only = list_refs_only;
TAILQ_FOREACH(pe, have_refs, entry)
fetchreq.n_have_refs++;
TAILQ_FOREACH(pe, wanted_branches, entry)
blob - cb84af601f60de1ffe71b64a1d15358acbcc11e8
blob + 123004c4d0700fee5e741fc9839cdcefe67d560b
--- libexec/got-fetch-pack/got-fetch-pack.c
+++ libexec/got-fetch-pack/got-fetch-pack.c
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, struct imsgbuf *ibuf)
+ struct got_pathlist_head *wanted_branches, int list_refs_only,
+ struct imsgbuf *ibuf)
{
const struct got_error *err = NULL;
char buf[GOT_FETCH_PKTMAX];
getprogname(), refname);
if (strncmp(refname, "refs/heads/", 11) == 0) {
- if (fetch_all_branches) {
+ if (fetch_all_branches || list_refs_only) {
found_branch = 1;
} else if (!TAILQ_EMPTY(wanted_branches)) {
TAILQ_FOREACH(pe, wanted_branches, entry) {
nref++;
}
+ if (list_refs_only)
+ goto done;
+
/* Abort if we haven't found any branch to fetch. */
if (!found_branch) {
err = got_error(GOT_ERR_FETCH_NO_BRANCH);
packfd = imsg.fd;
err = fetch_pack(fetchfd, packfd, &packid, &have_refs,
- fetch_req.fetch_all_branches, &wanted_branches, &ibuf);
+ fetch_req.fetch_all_branches, &wanted_branches,
+ fetch_req.list_refs_only, &ibuf);
done:
TAILQ_FOREACH(pe, &have_refs, entry) {
free((char *)pe->path);