Skip to content

Commit

Permalink
upload-pack: send symbolic ref information as capability
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Junio C Hamano committed Sep 18, 2013
1 parent a4d695d commit 7171d8c
Showing 1 changed file with 43 additions and 5 deletions.
48 changes: 43 additions & 5 deletions upload-pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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;

Expand Down

0 comments on commit 7171d8c

Please sign in to comment.