mirror of
https://git.proxmox.com/git/libgit2
synced 2025-05-29 22:25:04 +00:00
remote: dwim the refspecs according to the remote's advertised refs
As git allows you to store shorthand refspecs in the configuration, we need to do this ourselves.
This commit is contained in:
parent
528a4e24c6
commit
d84884571d
@ -17,6 +17,7 @@ struct git_refspec {
|
||||
unsigned int force :1,
|
||||
push : 1,
|
||||
pattern :1,
|
||||
dwim :1,
|
||||
matching :1;
|
||||
};
|
||||
|
||||
|
94
src/remote.c
94
src/remote.c
@ -632,28 +632,104 @@ int git_remote__get_http_proxy(git_remote *remote, bool use_ssl, char **proxy_ur
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int store_refs(git_remote_head *head, void *payload)
|
||||
{
|
||||
git_vector *refs = (git_vector *)payload;
|
||||
|
||||
return git_vector_insert(refs, head);
|
||||
}
|
||||
|
||||
static int dwim_refspecs(git_vector *refspecs, git_vector *refs)
|
||||
{
|
||||
git_buf buf = GIT_BUF_INIT;
|
||||
git_refspec *spec;
|
||||
size_t i, j, pos;
|
||||
git_remote_head key;
|
||||
|
||||
const char* formatters[] = {
|
||||
GIT_REFS_DIR "%s",
|
||||
GIT_REFS_TAGS_DIR "%s",
|
||||
GIT_REFS_HEADS_DIR "%s",
|
||||
NULL
|
||||
};
|
||||
|
||||
git_vector_foreach(refspecs, i, spec) {
|
||||
if (spec->dwim)
|
||||
continue;
|
||||
|
||||
/* shorthand on the lhs */
|
||||
if (git__prefixcmp(spec->src, GIT_REFS_DIR)) {
|
||||
for (j = 0; formatters[j]; j++) {
|
||||
git_buf_clear(&buf);
|
||||
if (git_buf_printf(&buf, formatters[j], spec->src) < 0)
|
||||
return -1;
|
||||
|
||||
key.name = (char *) git_buf_cstr(&buf);
|
||||
if (!git_vector_search(&pos, refs, &key)) {
|
||||
/* we found something to match the shorthand, set src to that */
|
||||
git__free(spec->src);
|
||||
spec->src = git_buf_detach(&buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (spec->dst && git__prefixcmp(spec->dst, GIT_REFS_DIR)) {
|
||||
/* if it starts with "remotes" then we just prepend "refs/" */
|
||||
if (!git__prefixcmp(spec->dst, "remotes/")) {
|
||||
git_buf_puts(&buf, GIT_REFS_DIR);
|
||||
} else {
|
||||
git_buf_puts(&buf, GIT_REFS_HEADS_DIR);
|
||||
}
|
||||
|
||||
if (git_buf_puts(&buf, spec->dst) < 0)
|
||||
return -1;
|
||||
|
||||
git__free(spec->dst);
|
||||
spec->dst = git_buf_detach(&buf);
|
||||
}
|
||||
|
||||
spec->dwim = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int remote_head_cmp(const void *_a, const void *_b)
|
||||
{
|
||||
const git_remote_head *a = (git_remote_head *) _a;
|
||||
const git_remote_head *b = (git_remote_head *) _b;
|
||||
|
||||
return git__strcmp_cb(a->name, b->name);
|
||||
}
|
||||
|
||||
int git_remote_download(
|
||||
git_remote *remote,
|
||||
git_transfer_progress_callback progress_cb,
|
||||
void *progress_payload)
|
||||
{
|
||||
int error;
|
||||
git_vector refs;
|
||||
|
||||
assert(remote);
|
||||
|
||||
if (git_vector_init(&refs, 16, remote_head_cmp) < 0)
|
||||
return -1;
|
||||
|
||||
if (git_remote_ls(remote, store_refs, &refs) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
error = dwim_refspecs(&remote->refspecs, &refs);
|
||||
git_vector_free(&refs);
|
||||
if (error < 0)
|
||||
return -1;
|
||||
|
||||
if ((error = git_fetch_negotiate(remote)) < 0)
|
||||
return error;
|
||||
|
||||
return git_fetch_download_pack(remote, progress_cb, progress_payload);
|
||||
}
|
||||
|
||||
static int update_tips_callback(git_remote_head *head, void *payload)
|
||||
{
|
||||
git_vector *refs = (git_vector *)payload;
|
||||
|
||||
return git_vector_insert(refs, head);
|
||||
}
|
||||
|
||||
static int remote_head_for_fetchspec_src(git_remote_head **out, git_vector *update_heads, const char *fetchspec_src)
|
||||
{
|
||||
unsigned int i;
|
||||
@ -814,7 +890,7 @@ static int update_tips_for_spec(git_remote *remote, git_refspec *spec, git_vecto
|
||||
if (!git_reference_is_valid_name(head->name))
|
||||
continue;
|
||||
|
||||
if (git_refspec_src_matches(spec, head->name)) {
|
||||
if (git_refspec_src_matches(spec, head->name) && spec->dst) {
|
||||
if (git_refspec_transform_r(&refname, spec, head->name) < 0)
|
||||
goto on_error;
|
||||
} else if (remote->download_tags != GIT_REMOTE_DOWNLOAD_TAGS_NONE) {
|
||||
@ -887,7 +963,7 @@ int git_remote_update_tips(git_remote *remote)
|
||||
if (git_vector_init(&refs, 16, NULL) < 0)
|
||||
return -1;
|
||||
|
||||
if (git_remote_ls(remote, update_tips_callback, &refs) < 0)
|
||||
if (git_remote_ls(remote, store_refs, &refs) < 0)
|
||||
goto on_error;
|
||||
|
||||
git_vector_foreach(&remote->refspecs, i, spec) {
|
||||
|
@ -100,3 +100,44 @@ void test_network_remote_local__nested_tags_are_completely_peeled(void)
|
||||
|
||||
cl_git_pass(git_remote_ls(remote, &ensure_peeled__cb, NULL));
|
||||
}
|
||||
|
||||
void test_network_remote_local__shorthand_fetch_refspec0(void)
|
||||
{
|
||||
const char *refspec = "master:remotes/sloppy/master";
|
||||
const char *refspec2 = "master:boh/sloppy/master";
|
||||
|
||||
git_reference *ref;
|
||||
|
||||
connect_to_local_repository(cl_fixture("testrepo.git"));
|
||||
cl_git_pass(git_remote_add_fetch(remote, refspec));
|
||||
cl_git_pass(git_remote_add_fetch(remote, refspec2));
|
||||
|
||||
cl_git_pass(git_remote_download(remote, NULL, NULL));
|
||||
cl_git_pass(git_remote_update_tips(remote));
|
||||
|
||||
cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/sloppy/master"));
|
||||
git_reference_free(ref);
|
||||
|
||||
cl_git_pass(git_reference_lookup(&ref, repo, "refs/heads/boh/sloppy/master"));
|
||||
git_reference_free(ref);
|
||||
}
|
||||
|
||||
void test_network_remote_local__shorthand_fetch_refspec1(void)
|
||||
{
|
||||
const char *refspec = "master";
|
||||
const char *refspec2 = "hard_tag";
|
||||
|
||||
git_reference *ref;
|
||||
|
||||
connect_to_local_repository(cl_fixture("testrepo.git"));
|
||||
git_remote_clear_refspecs(remote);
|
||||
cl_git_pass(git_remote_add_fetch(remote, refspec));
|
||||
cl_git_pass(git_remote_add_fetch(remote, refspec2));
|
||||
|
||||
cl_git_pass(git_remote_download(remote, NULL, NULL));
|
||||
cl_git_pass(git_remote_update_tips(remote));
|
||||
|
||||
cl_git_fail(git_reference_lookup(&ref, repo, "refs/remotes/master"));
|
||||
|
||||
cl_git_fail(git_reference_lookup(&ref, repo, "refs/tags/hard_tag"));
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user