Using the #next branch I've now hit a problem with git-fetch-pack master choosing refs/bases/master (I geuss created by StGIT) instead of refs/heads/master. The old upload-pack returned the refs in the order heads-tags-everything_else but the new one just goes for whatever order readdir() returns them in (modulo merging with packed refs). I actually can't see the difference that caused this right now, though. This is a _really ugly_ patch to fix that. I wonder if there's a more elegant solution to this. If you have your refs already packed, you should somehow unpack them and then pack them again. Signed-off-by: Petr Baudis <pasky@xxxxxxx> --- I send the patch with the hope that someone will be so irritated by it that he'll create a nicer one. ;-) refs.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 files changed, 36 insertions(+), 3 deletions(-) diff --git a/refs.c b/refs.c index 2cef2b4..9b3986a 100644 --- a/refs.c +++ b/refs.c @@ -91,7 +91,8 @@ static struct ref_list *get_packed_refs( return refs; } -static struct ref_list *get_ref_dir(const char *base, struct ref_list *list) +static struct ref_list *get_ref_dir(const char *base, struct ref_list *list, + char **except) { DIR *dir = opendir(git_path("%s", base)); @@ -121,7 +122,13 @@ static struct ref_list *get_ref_dir(cons if (stat(git_path("%s", ref), &st) < 0) continue; if (S_ISDIR(st.st_mode)) { - list = get_ref_dir(ref, list); + if (except) { + char **e; + for (e = except; *e; e++) + if (!strcmp(*e, ref)) + goto nextitem; + } + list = get_ref_dir(ref, list, except); continue; } if (!resolve_ref(ref, sha1, 1, &flag)) { @@ -129,6 +136,7 @@ static struct ref_list *get_ref_dir(cons continue; } list = add_ref(ref, sha1, flag, list); +nextitem:; } free(ref); closedir(dir); @@ -142,7 +150,23 @@ static struct ref_list *get_loose_refs(v static struct ref_list *refs = NULL; if (!did_refs) { - refs = get_ref_dir("refs", NULL); + /* We need to make sure refs/heads and refs/tags always + * go before everything else. */ + char *except[] = {"refs/heads", "refs/tags", NULL}; + struct ref_list *other_refs = NULL, *r; + + refs = get_ref_dir("refs/heads", NULL, NULL); + refs = get_ref_dir("refs/tags", refs, NULL); + + other_refs = get_ref_dir("refs", NULL, except); + if (refs) { + for (r = refs; r->next; r = r->next) + ; + r->next = other_refs; + } else { + refs = other_refs; + } + did_refs = 1; } return refs; @@ -298,10 +322,19 @@ static int do_for_each_ref(const char *b while (packed && loose) { struct ref_list *entry; int cmp = strcmp(packed->name, loose->name); + int packed_is_ht, loose_is_ht; if (!cmp) { packed = packed->next; continue; } + /* We need to make sure refs/heads and refs/tags always + * go before everything else. */ + packed_is_ht = !strncmp(packed->name, "refs/heads", 10) + || !strncmp(packed->name, "refs/tags", 9); + loose_is_ht = !strncmp(loose->name, "refs/heads", 10) + || !strncmp(loose->name, "refs/tags", 9); + if (packed_is_ht != loose_is_ht) + cmp = loose_is_ht - packed_is_ht; if (cmp > 0) { entry = loose; loose = loose->next; - To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html