Make ls-remote http://... list HEAD, like for git://...

This makes a struct ref able to represent a symref, and makes http.c
able to recognize one, and makes transport.c look for "HEAD" as a ref
in the list, and makes it dereference symrefs for the resulting ref,
if any.

Signed-off-by: Daniel Barkalow <barkalow@iabervon.org>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/cache.h b/cache.h
index 3fcc283..cfc1237 100644
--- a/cache.h
+++ b/cache.h
@@ -634,6 +634,7 @@
 	struct ref *next;
 	unsigned char old_sha1[20];
 	unsigned char new_sha1[20];
+	char *symref;
 	unsigned int force:1,
 		merge:1,
 		nonfastforward:1,
diff --git a/http.c b/http.c
index c8df13b..acf746a 100644
--- a/http.c
+++ b/http.c
@@ -626,7 +626,10 @@
 			strbuf_rtrim(&buffer);
 			if (buffer.len == 40)
 				ret = get_sha1_hex(buffer.buf, ref->old_sha1);
-			else
+			else if (!prefixcmp(buffer.buf, "ref: ")) {
+				ref->symref = xstrdup(buffer.buf + 5);
+				ret = 0;
+			} else
 				ret = 1;
 		} else {
 			ret = error("Couldn't get %s for %s\n%s",
diff --git a/remote.c b/remote.c
index 2d9af40..1504cd0 100644
--- a/remote.c
+++ b/remote.c
@@ -706,13 +706,22 @@
 	return ret;
 }
 
+void free_ref(struct ref *ref)
+{
+	if (!ref)
+		return;
+	free(ref->remote_status);
+	free(ref->symref);
+	free(ref);
+}
+
 void free_refs(struct ref *ref)
 {
 	struct ref *next;
 	while (ref) {
 		next = ref->next;
 		free(ref->peer_ref);
-		free(ref);
+		free_ref(ref);
 		ref = next;
 	}
 }
@@ -1172,3 +1181,15 @@
 
 	return 0;
 }
+
+int resolve_remote_symref(struct ref *ref, struct ref *list)
+{
+	if (!ref->symref)
+		return 0;
+	for (; list; list = list->next)
+		if (!strcmp(ref->symref, list->name)) {
+			hashcpy(ref->old_sha1, list->old_sha1);
+			return 0;
+		}
+	return 1;
+}
diff --git a/remote.h b/remote.h
index a38774b..ab82308 100644
--- a/remote.h
+++ b/remote.h
@@ -62,6 +62,8 @@
  */
 void free_refs(struct ref *ref);
 
+int resolve_remote_symref(struct ref *ref, struct ref *list);
+
 /*
  * Removes and frees any duplicate refs in the map.
  */
diff --git a/transport.c b/transport.c
index 393e0e8..b012a28 100644
--- a/transport.c
+++ b/transport.c
@@ -441,10 +441,14 @@
 	struct ref *ref = NULL;
 	struct ref *last_ref = NULL;
 
+	struct walker *walker;
+
 	if (!transport->data)
 		transport->data = get_http_walker(transport->url,
 						transport->remote);
 
+	walker = transport->data;
+
 	refs_url = xmalloc(strlen(transport->url) + 11);
 	sprintf(refs_url, "%s/info/refs", transport->url);
 
@@ -500,6 +504,16 @@
 
 	strbuf_release(&buffer);
 
+	ref = alloc_ref(strlen("HEAD") + 1);
+	strcpy(ref->name, "HEAD");
+	if (!walker->fetch_ref(walker, ref) &&
+	    !resolve_remote_symref(ref, refs)) {
+		ref->next = refs;
+		refs = ref;
+	} else {
+		free(ref);
+	}
+
 	return refs;
 }