mirror of
https://github.com/git/git.git
synced 2024-11-24 02:17:02 +08:00
upload-pack: send symbolic ref information as capability
One long-standing flaw in the pack transfer protocol was that there was no way to tell the other end which branch "HEAD" points at. With a capability "symref=HEAD:refs/heads/master", let the sender to tell the receiver what symbolic ref points at what ref. This capability can be repeated more than once to represent symbolic refs other than HEAD, such as "refs/remotes/origin/HEAD"). Add an infrastructure to collect symbolic refs, format them as extra capabilities and put it on the wire. For now, just send information on the "HEAD" and nothing else. Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
a4d695de0d
commit
7171d8c15f
@ -734,6 +734,16 @@ static int mark_our_ref(const char *refname, const unsigned char *sha1, int flag
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void format_symref_info(struct strbuf *buf, struct string_list *symref)
|
||||
{
|
||||
struct string_list_item *item;
|
||||
|
||||
if (!symref->nr)
|
||||
return;
|
||||
for_each_string_list_item(item, symref)
|
||||
strbuf_addf(buf, " symref=%s:%s", item->string, (char *)item->util);
|
||||
}
|
||||
|
||||
static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||
{
|
||||
static const char *capabilities = "multi_ack thin-pack side-band"
|
||||
@ -745,32 +755,60 @@ static int send_ref(const char *refname, const unsigned char *sha1, int flag, vo
|
||||
if (mark_our_ref(refname, sha1, flag, NULL))
|
||||
return 0;
|
||||
|
||||
if (capabilities)
|
||||
packet_write(1, "%s %s%c%s%s%s agent=%s\n",
|
||||
if (capabilities) {
|
||||
struct strbuf symref_info = STRBUF_INIT;
|
||||
|
||||
format_symref_info(&symref_info, cb_data);
|
||||
packet_write(1, "%s %s%c%s%s%s%s agent=%s\n",
|
||||
sha1_to_hex(sha1), refname_nons,
|
||||
0, capabilities,
|
||||
allow_tip_sha1_in_want ? " allow-tip-sha1-in-want" : "",
|
||||
stateless_rpc ? " no-done" : "",
|
||||
symref_info.buf,
|
||||
git_user_agent_sanitized());
|
||||
else
|
||||
strbuf_release(&symref_info);
|
||||
} else {
|
||||
packet_write(1, "%s %s\n", sha1_to_hex(sha1), refname_nons);
|
||||
}
|
||||
capabilities = NULL;
|
||||
if (!peel_ref(refname, peeled))
|
||||
packet_write(1, "%s %s^{}\n", sha1_to_hex(peeled), refname_nons);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int find_symref(const char *refname, const unsigned char *sha1, int flag,
|
||||
void *cb_data)
|
||||
{
|
||||
const char *symref_target;
|
||||
struct string_list_item *item;
|
||||
unsigned char unused[20];
|
||||
|
||||
if ((flag & REF_ISSYMREF) == 0)
|
||||
return 0;
|
||||
symref_target = resolve_ref_unsafe(refname, unused, 0, &flag);
|
||||
if (!symref_target || (flag & REF_ISSYMREF) == 0)
|
||||
die("'%s' is a symref but it is not?", refname);
|
||||
item = string_list_append(cb_data, refname);
|
||||
item->util = xstrdup(symref_target);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void upload_pack(void)
|
||||
{
|
||||
struct string_list symref = STRING_LIST_INIT_DUP;
|
||||
|
||||
head_ref_namespaced(find_symref, &symref);
|
||||
|
||||
if (advertise_refs || !stateless_rpc) {
|
||||
reset_timeout();
|
||||
head_ref_namespaced(send_ref, NULL);
|
||||
for_each_namespaced_ref(send_ref, NULL);
|
||||
head_ref_namespaced(send_ref, &symref);
|
||||
for_each_namespaced_ref(send_ref, &symref);
|
||||
packet_flush(1);
|
||||
} else {
|
||||
head_ref_namespaced(mark_our_ref, NULL);
|
||||
for_each_namespaced_ref(mark_our_ref, NULL);
|
||||
}
|
||||
string_list_clear(&symref, 1);
|
||||
if (advertise_refs)
|
||||
return;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user