commit - 1255c02f3e117fa4fd07f9cc6fbcf62383755e5d
commit + 99495ddb79841fe89b0746d35a49bb81e9220096
blob - 17b5f0720dd626a7af6459cf23be329bb9b96e21
blob + 4a92790860d73b08d6ba18a5daf45eed2583c62f
--- got/got.1
+++ got/got.1
.Pa config
files of the cloned repository to store the
.Ar repository-url
-and
+and any
.Ar branch
+or
+.Ar reference
arguments for future use by
.Cm got fetch
or
blob - 53829fbd5cf6cd49d4f93619417cf7218d2bbd1e
blob + 588f144e15210cef646e4d3b143f8cb74e7e5abe
--- got/got.c
+++ got/got.c
struct {
struct got_pathlist_head *symrefs;
struct got_pathlist_head *wanted_branches;
+ struct got_pathlist_head *wanted_refs;
const char *proto;
const char *host;
const char *port;
create_config_files(const char *proto, const char *host, const char *port,
const char *remote_repo_path, const char *git_url, int fetch_all_branches,
int mirror_references, struct got_pathlist_head *symrefs,
- struct got_pathlist_head *wanted_branches, struct got_repository *repo);
+ struct got_pathlist_head *wanted_branches,
+ struct got_pathlist_head *wanted_refs, struct got_repository *repo);
static const struct got_error *
fetch_progress(void *arg, const char *message, off_t packfile_size,
a->config_info.fetch_all_branches,
a->config_info.mirror_references,
a->config_info.symrefs,
- a->config_info.wanted_branches, a->repo);
+ a->config_info.wanted_branches,
+ a->config_info.wanted_refs, a->repo);
if (err)
return err;
a->configs_created = 1;
create_gotconfig(const char *proto, const char *host, const char *port,
const char *remote_repo_path, const char *default_branch,
int fetch_all_branches, struct got_pathlist_head *wanted_branches,
- int mirror_references, struct got_repository *repo)
+ struct got_pathlist_head *wanted_refs, int mirror_references,
+ struct got_repository *repo)
{
const struct got_error *err = NULL;
char *gotconfig_path = NULL;
char *gotconfig = NULL;
FILE *gotconfig_file = NULL;
const char *branchname = NULL;
- char *branches = NULL;
+ char *branches = NULL, *refs = NULL;
ssize_t n;
if (!fetch_all_branches && !TAILQ_EMPTY(wanted_branches)) {
if (asprintf(&branches, "\"%s\" ", branchname) == -1) {
err = got_error_from_errno("asprintf");
goto done;
+ }
+ }
+ if (!TAILQ_EMPTY(wanted_refs)) {
+ struct got_pathlist_entry *pe;
+ TAILQ_FOREACH(pe, wanted_refs, entry) {
+ char *s;
+ const char *refname = pe->path;
+ if (strncmp(refname, "refs/", 5) == 0)
+ branchname += 5;
+ if (asprintf(&s, "%s\"%s\" ",
+ refs ? refs : "", refname) == -1) {
+ err = got_error_from_errno("asprintf");
+ goto done;
+ }
+ free(refs);
+ refs = s;
}
}
"%s%s%s"
"\trepository \"%s\"\n"
"%s%s%s"
+ "%s%s%s"
"%s"
"%s"
"}\n",
port ? "\tport " : "", port ? port : "", port ? "\n" : "",
remote_repo_path, branches ? "\tbranch { " : "",
branches ? branches : "", branches ? "}\n" : "",
+ refs ? "\treference { " : "", refs ? refs : "", refs ? "}\n" : "",
mirror_references ? "\tmirror-references yes\n" : "",
fetch_all_branches ? "\tfetch-all-branches yes\n" : "") == -1) {
err = got_error_from_errno("asprintf");
static const struct got_error *
create_gitconfig(const char *git_url, const char *default_branch,
int fetch_all_branches, struct got_pathlist_head *wanted_branches,
- int mirror_references, struct got_repository *repo)
+ struct got_pathlist_head *wanted_refs, int mirror_references,
+ struct got_repository *repo)
{
const struct got_error *err = NULL;
char *gitconfig_path = NULL;
char *gitconfig = NULL;
FILE *gitconfig_file = NULL;
- char *branches = NULL;
+ char *branches = NULL, *refs = NULL;
const char *branchname, *mirror = NULL;
ssize_t n;
branchname) == -1) {
err = got_error_from_errno("asprintf");
goto done;
+ }
+ }
+ if (!mirror_references && !TAILQ_EMPTY(wanted_refs)) {
+ struct got_pathlist_entry *pe;
+ TAILQ_FOREACH(pe, wanted_refs, entry) {
+ char *s;
+ const char *refname = pe->path;
+ if (strncmp(refname, "refs/", 5) == 0)
+ refname += 5;
+ if (asprintf(&s,
+ "%s\tfetch = +refs/%s:refs/remotes/%s/%s\n",
+ refs ? refs : "",
+ refname, GOT_FETCH_DEFAULT_REMOTE_NAME,
+ refname) == -1) {
+ err = got_error_from_errno("asprintf");
+ goto done;
+ }
+ free(refs);
+ refs = s;
}
}
+
if (asprintf(&gitconfig,
"[remote \"%s\"]\n"
"\turl = %s\n"
"%s"
+ "%s"
"%s",
GOT_FETCH_DEFAULT_REMOTE_NAME, git_url, branches ? branches : "",
- mirror ? mirror : "") == -1) {
+ refs ? refs : "", mirror ? mirror : "") == -1) {
err = got_error_from_errno("asprintf");
goto done;
}
create_config_files(const char *proto, const char *host, const char *port,
const char *remote_repo_path, const char *git_url, int fetch_all_branches,
int mirror_references, struct got_pathlist_head *symrefs,
- struct got_pathlist_head *wanted_branches, struct got_repository *repo)
+ struct got_pathlist_head *wanted_branches,
+ struct got_pathlist_head *wanted_refs, struct got_repository *repo)
{
const struct got_error *err = NULL;
const char *default_branch = NULL;
/* Create got.conf(5). */
err = create_gotconfig(proto, host, port, remote_repo_path,
default_branch, fetch_all_branches, wanted_branches,
- mirror_references, repo);
+ wanted_refs, mirror_references, repo);
if (err)
return err;
/* Create a config file Git can understand. */
return create_gitconfig(git_url, default_branch, fetch_all_branches,
- wanted_branches, mirror_references, repo);
+ wanted_branches, wanted_refs, mirror_references, repo);
}
static const struct got_error *
fpa.repo = repo;
fpa.config_info.symrefs = &symrefs;
fpa.config_info.wanted_branches = &wanted_branches;
+ fpa.config_info.wanted_refs = &wanted_refs;
fpa.config_info.proto = proto;
fpa.config_info.host = host;
fpa.config_info.port = port;
for (i = 0; i < remote->nbranches; i++) {
got_pathlist_append(&wanted_branches,
remote->branches[i], NULL);
+ }
+ }
+ if (TAILQ_EMPTY(&wanted_refs)) {
+ for (i = 0; i < remote->nrefs; i++) {
+ got_pathlist_append(&wanted_refs,
+ remote->refs[i], NULL);
}
}
blob - b4fe08c8227db5b27b1d37237b58cef45adbbdb8
blob + 846205a43f056559a960ab6d0c0ebb5076e6ba20
--- got/got.conf.5
+++ got/got.conf.5
option, and any
.Cm branch
configuration settings for this remote repository will be ignored.
+.It Ic reference Brq Ar reference ...
+Specify one or more arbitrary references which
+.Cm got fetch
+should fetch by default, in addition to the branches and tags that will
+be fetched.
+The list of references specified here can be overridden at the
+.Cm got fetch
+command line with the
+.Fl R
+option.
+.Cm got fetch
+will refuse to fetch references from the remote repository's
+.Dq refs/remotes/
+or
+.Dq refs/got/
+namespace.
+In any case, references in the
+.Dq refs/tags/
+namespace will always be fetched and mapped directly to local references
+in the same namespace.
.It Ic mirror-references Ar yes | no
This option controls the behaviour of
.Cm got fetch
blob - 8cc337b5791e1261b077f0b81458c6a6fa7a3672
blob + 56d5bf0fafeca5450bd82577d1eb163c53c74a9e
--- include/got_repository.h
+++ include/got_repository.h
/* Branches to fetch by default. */
int nbranches;
char **branches;
+
+ /* Other arbitrary references to fetch by default. */
+ int nrefs;
+ char **refs;
};
/*
blob - fba84c449fe93dd2034e7f391c26ffcc869e1bd9
blob + 8dbb8d0ba06da245e90c69b5db067658d496e0b0
--- lib/got_lib_privsep.h
+++ lib/got_lib_privsep.h
int mirror_references;
int fetch_all_branches;
int nbranches;
+ int nrefs;
/* Followed by name_len + url_len data bytes. */
/* Followed by nbranches GOT_IMSG_GITCONFIG_STR_VAL messages. */
+ /* Followed by nrefs GOT_IMSG_GITCONFIG_STR_VAL messages. */
} __attribute__((__packed__));
/*
blob - a4c526b34cd96016e55eeea3f87de869709e3eed
blob + 4fb6f24032dafb92991f1671b8252d6b045fa81b
--- lib/privsep.c
+++ lib/privsep.c
for (i = 0; i < remote->nbranches; i++)
free(remote->branches[i]);
free(remote->branches);
+ for (i = 0; i < remote->nrefs; i++)
+ free(remote->refs[i]);
+ free(remote->refs);
}
const struct got_error *
remote->fetch_all_branches = iremote.fetch_all_branches;
remote->nbranches = 0;
remote->branches = NULL;
+ remote->nrefs = 0;
+ remote->refs = NULL;
(*nremotes)++;
break;
default:
}
remote->branches[i] = branch;
remote->nbranches++;
+ }
+ if (iremote.nrefs > 0) {
+ remote->refs = recallocarray(NULL, 0,
+ iremote.nrefs, sizeof(char *));
+ if (remote->refs == NULL) {
+ err = got_error_from_errno("calloc");
+ free_remote_data(remote);
+ break;
+ }
}
+ remote->nrefs = 0;
+ for (i = 0; i < iremote.nrefs; i++) {
+ char *ref;
+ err = got_privsep_recv_gotconfig_str(&ref,
+ ibuf);
+ if (err) {
+ free_remote_data(remote);
+ goto done;
+ }
+ remote->refs[i] = ref;
+ remote->nrefs++;
+ }
(*nremotes)++;
break;
default:
blob - 70e993212984e95be5ad134c51a5705fd98e7417
blob + 2fe537dc6e1f300194d9d5d74a0b2e170c9a0010
--- libexec/got-read-gotconfig/got-read-gotconfig.c
+++ libexec/got-read-gotconfig/got-read-gotconfig.c
size_t len = sizeof(iremote);
struct ibuf *wbuf;
struct node_branch *branch;
- int nbranches = 0;
+ struct node_ref *ref;
+ int nbranches = 0, nrefs = 0;
branch = repo->branch;
while (branch) {
branch = branch->next;
nbranches++;
+ }
+
+ ref = repo->ref;
+ while (ref) {
+ ref = ref->next;
+ nrefs++;
}
iremote.nbranches = nbranches;
+ iremote.nrefs = nrefs;
iremote.mirror_references = repo->mirror_references;
iremote.fetch_all_branches = repo->fetch_all_branches;
break;
branch = branch->next;
}
+
+ ref = repo->ref;
+ while (ref) {
+ err = send_gotconfig_str(ibuf, ref->ref_name);
+ if (err)
+ break;
+ ref = ref->next;
+ }
}
free(url);
blob - 212b87b75f0b8d817b88f63b9c5d417d6499a93c
blob + 5f1429f97e35fc3f76e9a1054a203794f783e4c7
--- libexec/got-read-gotconfig/gotconfig.h
+++ libexec/got-read-gotconfig/gotconfig.h
struct node_branch *tail;
};
+struct node_ref {
+ char *ref_name;
+ struct node_ref *next;
+ struct node_ref *tail;
+};
+
struct gotconfig_remote_repo {
TAILQ_ENTRY(gotconfig_remote_repo) entry;
char *name;
int mirror_references;
int fetch_all_branches;
struct node_branch *branch;
+ struct node_ref *ref;
};
TAILQ_HEAD(gotconfig_remote_repo_list, gotconfig_remote_repo);
blob - 07d4556e67f6c9a4b929b7ada11df90e97e2ebd7
blob + 821eff3050b8f45ad0cd9b5475874eca2aa1117d
--- libexec/got-read-gotconfig/parse.y
+++ libexec/got-read-gotconfig/parse.y
long long number;
char *string;
struct node_branch *branch;
+ struct node_ref *ref;
} v;
int lineno;
} YYSTYPE;
%token ERROR
%token REMOTE REPOSITORY SERVER PORT PROTOCOL MIRROR_REFERENCES BRANCH
-%token AUTHOR FETCH_ALL_BRANCHES
+%token AUTHOR FETCH_ALL_BRANCHES REFERENCE
%token <v.string> STRING
%token <v.number> NUMBER
%type <v.number> boolean portplain
%type <v.string> numberstring
%type <v.branch> branch xbranch branch_list
+%type <v.ref> ref xref ref_list
%%
$$ = $1;
}
;
-
+ref : /* empty */ { $$ = NULL; }
+ | xref { $$ = $1; }
+ | '{' optnl ref_list '}' { $$ = $3; }
+ ;
+xref : STRING {
+ $$ = calloc(1, sizeof(struct node_ref));
+ if ($$ == NULL) {
+ yyerror("calloc");
+ YYERROR;
+ }
+ $$->ref_name = $1;
+ $$->tail = $$;
+ }
+ ;
+ref_list : xref optnl { $$ = $1; }
+ | ref_list comma xref optnl {
+ $1->tail->next = $3;
+ $1->tail = $3;
+ $$ = $1;
+ }
+ ;
remoteopts2 : remoteopts2 remoteopts1 nl
| remoteopts1 optnl
;
}
| BRANCH branch {
remote->branch = $2;
+ }
+ | REFERENCE ref {
+ remote->ref = $2;
}
;
remote : REMOTE STRING {
{"mirror-references", MIRROR_REFERENCES},
{"port", PORT},
{"protocol", PROTOCOL},
+ {"reference", REFERENCE},
{"remote", REMOTE},
{"repository", REPOSITORY},
{"server", SERVER},
blob - b36a5f40a0b3db3547f0990d5fd2b2b947fc4821
blob + 44c5e030d3c0d68974cecd35b85f6edabc096ee3
--- regress/cmdline/clone.sh
+++ regress/cmdline/clone.sh
protocol ssh
repository "$testroot/repo"
branch { "master" }
+ reference { "hoo" }
}
EOF
cmp -s $testroot/repo-clone/got.conf $testroot/got.conf.expected
[remote "origin"]
url = ssh://127.0.0.1$testroot/repo
fetch = +refs/heads/master:refs/remotes/origin/master
+ fetch = +refs/hoo:refs/remotes/origin/hoo
EOF
cmp -s $testroot/repo-clone/config $testroot/config.expected
ret="$?"
protocol ssh
repository "$testroot/repo"
branch { "foo" }
+ reference { "hoo/boo/zoo" }
}
EOF
cmp -s $testroot/repo-clone/got.conf $testroot/got.conf.expected
[remote "origin"]
url = ssh://127.0.0.1$testroot/repo
fetch = +refs/heads/foo:refs/remotes/origin/foo
+ fetch = +refs/hoo/boo/zoo:refs/remotes/origin/hoo/boo/zoo
EOF
cmp -s $testroot/repo-clone/config $testroot/config.expected
ret="$?"
protocol ssh
repository "$testroot/repo"
branch { "master" }
+ reference { "hoo" }
mirror-references yes
}
EOF
blob - 0af6ce58eaded1d0d98284d9acdf7306a7405494
blob + fa4ff0524821f4d1b0e9bc984f084f50e656bdb0
--- regress/cmdline/fetch.sh
+++ regress/cmdline/fetch.sh
ret="$?"
if [ "$ret" != "0" ]; then
diff -u $testroot/stdout.expected $testroot/stdout
- fi
- test_done "$testroot" "$ret"
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+cat > $testroot/repo-clone/got.conf <<EOF
+remote "origin" {
+ protocol ssh
+ server 127.0.0.1
+ repository "$testroot/repo"
+ branch { "foo" }
+ reference { "hoo/boo/zoo" }
}
+EOF
+ (cd $testroot/repo-clone && got fetch -q > $testroot/stdout)
+ local tag_id=`got ref -r $testroot/repo -l \
+ | grep "^refs/tags/1.0" | tr -d ' ' | cut -d: -f2`
+ echo "HEAD: refs/heads/master" > $testroot/stdout.expected
+ echo "refs/heads/foo: $commit_id" >> $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_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
+
+ got ref -l -r $testroot/repo-clone > $testroot/stdout
+
+ cmp -s $testroot/stdout $testroot/stdout.expected
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
+}
+
test_parseargs "$@"
run_test test_fetch_basic
run_test test_fetch_list