Merge branch 'jc/fetch-raw-sha1'
Allows requests to fetch objects at any tip of refs (including hidden ones). It seems that there may be use cases even outside Gerrit (e.g. $gmane/215701). * jc/fetch-raw-sha1: fetch: fetch objects by their exact SHA-1 object names upload-pack: optionally allow fetching from the tips of hidden refs fetch: use struct ref to represent refs to be fetched parse_fetch_refspec(): clarify the codeflow a bit
This commit is contained in:
101
fetch-pack.c
101
fetch-pack.c
@ -36,7 +36,7 @@ static int marked;
|
||||
#define MAX_IN_VAIN 256
|
||||
|
||||
static struct commit_list *rev_list;
|
||||
static int non_common_revs, multi_ack, use_sideband;
|
||||
static int non_common_revs, multi_ack, use_sideband, allow_tip_sha1_in_want;
|
||||
|
||||
static void rev_list_push(struct commit *commit, int mark)
|
||||
{
|
||||
@ -520,47 +520,37 @@ static void mark_recent_complete_commits(struct fetch_pack_args *args,
|
||||
}
|
||||
}
|
||||
|
||||
static int non_matching_ref(struct string_list_item *item, void *unused)
|
||||
{
|
||||
if (item->util) {
|
||||
item->util = NULL;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void filter_refs(struct fetch_pack_args *args,
|
||||
struct ref **refs, struct string_list *sought)
|
||||
struct ref **refs,
|
||||
struct ref **sought, int nr_sought)
|
||||
{
|
||||
struct ref *newlist = NULL;
|
||||
struct ref **newtail = &newlist;
|
||||
struct ref *ref, *next;
|
||||
int sought_pos;
|
||||
int i;
|
||||
|
||||
sought_pos = 0;
|
||||
i = 0;
|
||||
for (ref = *refs; ref; ref = next) {
|
||||
int keep = 0;
|
||||
next = ref->next;
|
||||
|
||||
if (!memcmp(ref->name, "refs/", 5) &&
|
||||
check_refname_format(ref->name + 5, 0))
|
||||
; /* trash */
|
||||
else {
|
||||
while (sought_pos < sought->nr) {
|
||||
int cmp = strcmp(ref->name, sought->items[sought_pos].string);
|
||||
while (i < nr_sought) {
|
||||
int cmp = strcmp(ref->name, sought[i]->name);
|
||||
if (cmp < 0)
|
||||
break; /* definitely do not have it */
|
||||
else if (cmp == 0) {
|
||||
keep = 1; /* definitely have it */
|
||||
sought->items[sought_pos++].util = "matched";
|
||||
break;
|
||||
sought[i]->matched = 1;
|
||||
}
|
||||
else
|
||||
sought_pos++; /* might have it; keep looking */
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (! keep && args->fetch_all &&
|
||||
if (!keep && args->fetch_all &&
|
||||
(!args->depth || prefixcmp(ref->name, "refs/tags/")))
|
||||
keep = 1;
|
||||
|
||||
@ -573,7 +563,21 @@ static void filter_refs(struct fetch_pack_args *args,
|
||||
}
|
||||
}
|
||||
|
||||
filter_string_list(sought, 0, non_matching_ref, NULL);
|
||||
/* Append unmatched requests to the list */
|
||||
if (allow_tip_sha1_in_want) {
|
||||
for (i = 0; i < nr_sought; i++) {
|
||||
ref = sought[i];
|
||||
if (ref->matched)
|
||||
continue;
|
||||
if (get_sha1_hex(ref->name, ref->old_sha1))
|
||||
continue;
|
||||
|
||||
ref->matched = 1;
|
||||
*newtail = ref;
|
||||
ref->next = NULL;
|
||||
newtail = &ref->next;
|
||||
}
|
||||
}
|
||||
*refs = newlist;
|
||||
}
|
||||
|
||||
@ -583,7 +587,8 @@ static void mark_alternate_complete(const struct ref *ref, void *unused)
|
||||
}
|
||||
|
||||
static int everything_local(struct fetch_pack_args *args,
|
||||
struct ref **refs, struct string_list *sought)
|
||||
struct ref **refs,
|
||||
struct ref **sought, int nr_sought)
|
||||
{
|
||||
struct ref *ref;
|
||||
int retval;
|
||||
@ -637,7 +642,7 @@ static int everything_local(struct fetch_pack_args *args,
|
||||
}
|
||||
}
|
||||
|
||||
filter_refs(args, refs, sought);
|
||||
filter_refs(args, refs, sought, nr_sought);
|
||||
|
||||
for (retval = 1, ref = *refs; ref ; ref = ref->next) {
|
||||
const unsigned char *remote = ref->old_sha1;
|
||||
@ -767,10 +772,17 @@ static int get_pack(struct fetch_pack_args *args,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmp_ref_by_name(const void *a_, const void *b_)
|
||||
{
|
||||
const struct ref *a = *((const struct ref **)a_);
|
||||
const struct ref *b = *((const struct ref **)b_);
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
static struct ref *do_fetch_pack(struct fetch_pack_args *args,
|
||||
int fd[2],
|
||||
const struct ref *orig_ref,
|
||||
struct string_list *sought,
|
||||
struct ref **sought, int nr_sought,
|
||||
char **pack_lockfile)
|
||||
{
|
||||
struct ref *ref = copy_ref_list(orig_ref);
|
||||
@ -779,6 +791,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
|
||||
int agent_len;
|
||||
|
||||
sort_ref_list(&ref, ref_compare_name);
|
||||
qsort(sought, nr_sought, sizeof(*sought), cmp_ref_by_name);
|
||||
|
||||
if (is_repository_shallow() && !server_supports("shallow"))
|
||||
die("Server does not support shallow clients");
|
||||
@ -808,6 +821,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
|
||||
fprintf(stderr, "Server supports side-band\n");
|
||||
use_sideband = 1;
|
||||
}
|
||||
if (server_supports("allow-tip-sha1-in-want")) {
|
||||
if (args->verbose)
|
||||
fprintf(stderr, "Server supports allow-tip-sha1-in-want\n");
|
||||
allow_tip_sha1_in_want = 1;
|
||||
}
|
||||
if (!server_supports("thin-pack"))
|
||||
args->use_thin_pack = 0;
|
||||
if (!server_supports("no-progress"))
|
||||
@ -827,7 +845,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
|
||||
agent_len, agent_feature);
|
||||
}
|
||||
|
||||
if (everything_local(args, &ref, sought)) {
|
||||
if (everything_local(args, &ref, sought, nr_sought)) {
|
||||
packet_flush(fd[1]);
|
||||
goto all_done;
|
||||
}
|
||||
@ -890,11 +908,32 @@ static void fetch_pack_setup(void)
|
||||
did_setup = 1;
|
||||
}
|
||||
|
||||
static int remove_duplicates_in_refs(struct ref **ref, int nr)
|
||||
{
|
||||
struct string_list names = STRING_LIST_INIT_NODUP;
|
||||
int src, dst;
|
||||
|
||||
for (src = dst = 0; src < nr; src++) {
|
||||
struct string_list_item *item;
|
||||
item = string_list_insert(&names, ref[src]->name);
|
||||
if (item->util)
|
||||
continue; /* already have it */
|
||||
item->util = ref[src];
|
||||
if (src != dst)
|
||||
ref[dst] = ref[src];
|
||||
dst++;
|
||||
}
|
||||
for (src = dst; src < nr; src++)
|
||||
ref[src] = NULL;
|
||||
string_list_clear(&names, 0);
|
||||
return dst;
|
||||
}
|
||||
|
||||
struct ref *fetch_pack(struct fetch_pack_args *args,
|
||||
int fd[], struct child_process *conn,
|
||||
const struct ref *ref,
|
||||
const char *dest,
|
||||
struct string_list *sought,
|
||||
struct ref **sought, int nr_sought,
|
||||
char **pack_lockfile)
|
||||
{
|
||||
struct stat st;
|
||||
@ -906,16 +945,14 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
|
||||
st.st_mtime = 0;
|
||||
}
|
||||
|
||||
if (sought->nr) {
|
||||
sort_string_list(sought);
|
||||
string_list_remove_duplicates(sought, 0);
|
||||
}
|
||||
if (nr_sought)
|
||||
nr_sought = remove_duplicates_in_refs(sought, nr_sought);
|
||||
|
||||
if (!ref) {
|
||||
packet_flush(fd[1]);
|
||||
die("no matching remote head");
|
||||
}
|
||||
ref_cpy = do_fetch_pack(args, fd, ref, sought, pack_lockfile);
|
||||
ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, pack_lockfile);
|
||||
|
||||
if (args->depth > 0) {
|
||||
static struct lock_file lock;
|
||||
|
||||
Reference in New Issue
Block a user