fetch: fetch objects by their exact SHA-1 object names
Teach "git fetch" to accept an exact SHA-1 object name the user may obtain out of band on the LHS of a pathspec, and send it on a "want" message when the server side advertises the allow-tip-sha1-in-want capability. Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
390eb36b0a
commit
6e7b66eebd
22
fetch-pack.c
22
fetch-pack.c
@ -36,7 +36,7 @@ static int marked;
|
|||||||
#define MAX_IN_VAIN 256
|
#define MAX_IN_VAIN 256
|
||||||
|
|
||||||
static struct commit_list *rev_list;
|
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)
|
static void rev_list_push(struct commit *commit, int mark)
|
||||||
{
|
{
|
||||||
@ -563,6 +563,21 @@ static void filter_refs(struct fetch_pack_args *args,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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;
|
*refs = newlist;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -803,6 +818,11 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
|
|||||||
fprintf(stderr, "Server supports side-band\n");
|
fprintf(stderr, "Server supports side-band\n");
|
||||||
use_sideband = 1;
|
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"))
|
if (!server_supports("thin-pack"))
|
||||||
args->use_thin_pack = 0;
|
args->use_thin_pack = 0;
|
||||||
if (!server_supports("no-progress"))
|
if (!server_supports("no-progress"))
|
||||||
|
12
remote.c
12
remote.c
@ -15,6 +15,7 @@ static struct refspec s_tag_refspec = {
|
|||||||
0,
|
0,
|
||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
|
0,
|
||||||
"refs/tags/*",
|
"refs/tags/*",
|
||||||
"refs/tags/*"
|
"refs/tags/*"
|
||||||
};
|
};
|
||||||
@ -565,9 +566,13 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
|
|||||||
flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
|
flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
|
||||||
|
|
||||||
if (fetch) {
|
if (fetch) {
|
||||||
|
unsigned char unused[40];
|
||||||
|
|
||||||
/* LHS */
|
/* LHS */
|
||||||
if (!*rs[i].src)
|
if (!*rs[i].src)
|
||||||
; /* empty is ok; it means "HEAD" */
|
; /* empty is ok; it means "HEAD" */
|
||||||
|
else if (llen == 40 && !get_sha1_hex(rs[i].src, unused))
|
||||||
|
rs[i].exact_sha1 = 1; /* ok */
|
||||||
else if (!check_refname_format(rs[i].src, flags))
|
else if (!check_refname_format(rs[i].src, flags))
|
||||||
; /* valid looking ref is ok */
|
; /* valid looking ref is ok */
|
||||||
else
|
else
|
||||||
@ -1495,7 +1500,12 @@ int get_fetch_map(const struct ref *remote_refs,
|
|||||||
} else {
|
} else {
|
||||||
const char *name = refspec->src[0] ? refspec->src : "HEAD";
|
const char *name = refspec->src[0] ? refspec->src : "HEAD";
|
||||||
|
|
||||||
ref_map = get_remote_ref(remote_refs, name);
|
if (refspec->exact_sha1) {
|
||||||
|
ref_map = alloc_ref(name);
|
||||||
|
get_sha1_hex(name, ref_map->old_sha1);
|
||||||
|
} else {
|
||||||
|
ref_map = get_remote_ref(remote_refs, name);
|
||||||
|
}
|
||||||
if (!missing_ok && !ref_map)
|
if (!missing_ok && !ref_map)
|
||||||
die("Couldn't find remote ref %s", name);
|
die("Couldn't find remote ref %s", name);
|
||||||
if (ref_map) {
|
if (ref_map) {
|
||||||
|
1
remote.h
1
remote.h
@ -62,6 +62,7 @@ struct refspec {
|
|||||||
unsigned force : 1;
|
unsigned force : 1;
|
||||||
unsigned pattern : 1;
|
unsigned pattern : 1;
|
||||||
unsigned matching : 1;
|
unsigned matching : 1;
|
||||||
|
unsigned exact_sha1 : 1;
|
||||||
|
|
||||||
char *src;
|
char *src;
|
||||||
char *dst;
|
char *dst;
|
||||||
|
@ -1064,4 +1064,38 @@ do
|
|||||||
'
|
'
|
||||||
done
|
done
|
||||||
|
|
||||||
|
test_expect_success 'fetch exact SHA1' '
|
||||||
|
mk_test heads/master hidden/one &&
|
||||||
|
git push testrepo master:refs/hidden/one &&
|
||||||
|
(
|
||||||
|
cd testrepo &&
|
||||||
|
git config transfer.hiderefs refs/hidden
|
||||||
|
) &&
|
||||||
|
check_push_result $the_commit hidden/one &&
|
||||||
|
|
||||||
|
mk_child child &&
|
||||||
|
(
|
||||||
|
cd child &&
|
||||||
|
|
||||||
|
# make sure $the_commit does not exist here
|
||||||
|
git repack -a -d &&
|
||||||
|
git prune &&
|
||||||
|
test_must_fail git cat-file -t $the_commit &&
|
||||||
|
|
||||||
|
# fetching the hidden object should fail by default
|
||||||
|
test_must_fail git fetch -v ../testrepo $the_commit:refs/heads/copy &&
|
||||||
|
test_must_fail git rev-parse --verify refs/heads/copy &&
|
||||||
|
|
||||||
|
# the server side can allow it to succeed
|
||||||
|
(
|
||||||
|
cd ../testrepo &&
|
||||||
|
git config uploadpack.allowtipsha1inwant true
|
||||||
|
) &&
|
||||||
|
|
||||||
|
git fetch -v ../testrepo $the_commit:refs/heads/copy &&
|
||||||
|
result=$(git rev-parse --verify refs/heads/copy) &&
|
||||||
|
test "$the_commit" = "$result"
|
||||||
|
)
|
||||||
|
'
|
||||||
|
|
||||||
test_done
|
test_done
|
||||||
|
Loading…
x
Reference in New Issue
Block a user