[RFC][PATCH] for_each_ref() returning heads in wrong order

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]