stagit

sort branches and tags by time (descending)

In general version tags are done in chronological order, so this will have a
better sorting for tagged (versioned) releases.

Request from Caltlgin Stsodaat and others, thanks!

Hiltjo Posthuma contact@arjunchoudhary.com

commit: e654152 parent: d01987f
1 files changed, 92 insertions(+), 72 deletions(-)
Mstagit.c+92-72
M · stagit.c +92, -72
  1@@ -48,6 +48,12 @@ struct commitinfo {
  2 	size_t ndeltas;
  3 };
  4 
  5+/* reference and associated data for sorting */
  6+struct referenceinfo {
  7+	struct git_reference *ref;
  8+	struct commitinfo *ci;
  9+};
 10+
 11 static git_repository *repo;
 12 
 13 static const char *relpath = "";
 14@@ -938,113 +944,127 @@ writefiles(FILE *fp, const git_oid *id)
 15 int
 16 refs_cmp(const void *v1, const void *v2)
 17 {
 18-	git_reference *r1 = (*(git_reference **)v1);
 19-	git_reference *r2 = (*(git_reference **)v2);
 20+	struct referenceinfo *r1 = (struct referenceinfo *)v1;
 21+	struct referenceinfo *r2 = (struct referenceinfo *)v2;
 22+	time_t t1, t2;
 23 	int r;
 24 
 25-	if ((r = git_reference_is_branch(r1) - git_reference_is_branch(r2)))
 26+	if ((r = git_reference_is_tag(r1->ref) - git_reference_is_tag(r2->ref)))
 27+		return r;
 28+
 29+	t1 = r1->ci->author ? r1->ci->author->when.time : 0;
 30+	t2 = r2->ci->author ? r2->ci->author->when.time : 0;
 31+	if ((r = t1 > t2 ? -1 : (t1 == t2 ? 0 : 1)))
 32 		return r;
 33 
 34-	return strcmp(git_reference_shorthand(r1),
 35-	              git_reference_shorthand(r2));
 36+	return strcmp(git_reference_shorthand(r1->ref),
 37+	              git_reference_shorthand(r2->ref));
 38 }
 39 
 40 int
 41 writerefs(FILE *fp)
 42 {
 43+	struct referenceinfo *ris = NULL;
 44 	struct commitinfo *ci;
 45 	const git_oid *id = NULL;
 46 	git_object *obj = NULL;
 47 	git_reference *dref = NULL, *r, *ref = NULL;
 48 	git_reference_iterator *it = NULL;
 49-	git_reference **refs = NULL;
 50 	size_t count, i, j, refcount;
 51 	const char *titles[] = { "Branches", "Tags" };
 52 	const char *ids[] = { "branches", "tags" };
 53-	const char *name;
 54+	const char *s;
 55 
 56 	if (git_reference_iterator_new(&it, repo))
 57 		return -1;
 58 
 59-	for (refcount = 0; !git_reference_next(&ref, it); refcount++) {
 60-		if (!(refs = reallocarray(refs, refcount + 1, sizeof(git_reference *))))
 61-			err(1, "realloc");
 62-		refs[refcount] = ref;
 63-	}
 64-	git_reference_iterator_free(it);
 65-
 66-	/* sort by type then shorthand name */
 67-	qsort(refs, refcount, sizeof(git_reference *), refs_cmp);
 68-
 69-	for (j = 0; j < 2; j++) {
 70-		for (i = 0, count = 0; i < refcount; i++) {
 71-			if (!(git_reference_is_branch(refs[i]) && j == 0) &&
 72-			    !(git_reference_is_tag(refs[i]) && j == 1))
 73-				continue;
 74+	for (refcount = 0; !git_reference_next(&ref, it); ) {
 75+		if (!git_reference_is_branch(ref) && !git_reference_is_tag(ref)) {
 76+			git_reference_free(ref);
 77+			ref = NULL;
 78+			continue;
 79+		}
 80 
 81-			switch (git_reference_type(refs[i])) {
 82-			case GIT_REF_SYMBOLIC:
 83-				if (git_reference_resolve(&dref, refs[i]))
 84-					goto err;
 85-				r = dref;
 86-				break;
 87-			case GIT_REF_OID:
 88-				r = refs[i];
 89-				break;
 90-			default:
 91-				continue;
 92-			}
 93-			if (!git_reference_target(r) ||
 94-			    git_reference_peel(&obj, r, GIT_OBJ_ANY))
 95+		switch (git_reference_type(ref)) {
 96+		case GIT_REF_SYMBOLIC:
 97+			if (git_reference_resolve(&dref, ref))
 98 				goto err;
 99-			if (!(id = git_object_id(obj)))
100-				goto err;
101-			if (!(ci = commitinfo_getbyoid(id)))
102-				break;
103+			r = dref;
104+			break;
105+		case GIT_REF_OID:
106+			r = ref;
107+			break;
108+		default:
109+			continue;
110+		}
111+		if (!git_reference_target(r) ||
112+		    git_reference_peel(&obj, r, GIT_OBJ_ANY))
113+			goto err;
114+		if (!(id = git_object_id(obj)))
115+			goto err;
116+		if (!(ci = commitinfo_getbyoid(id)))
117+			break;
118 
119-			/* print header if it has an entry (first). */
120-			if (++count == 1) {
121-				fprintf(fp, "<h2>%s</h2><table id=\"%s\">"
122-			                "<thead>\n<tr><td><b>Name</b></td>"
123-				        "<td><b>Last commit date</b></td>"
124-				        "<td><b>Author</b></td>\n</tr>\n"
125-				        "</thead><tbody>\n",
126-				         titles[j], ids[j]);
127-			}
128+		if (!(ris = reallocarray(ris, refcount + 1, sizeof(*ris))))
129+			err(1, "realloc");
130+		ris[refcount].ci = ci;
131+		ris[refcount].ref = r;
132+		refcount++;
133 
134-			relpath = "";
135-			name = git_reference_shorthand(r);
136+		git_object_free(obj);
137+		obj = NULL;
138+		git_reference_free(dref);
139+		dref = NULL;
140+	}
141+	git_reference_iterator_free(it);
142 
143-			fputs("<tr><td>", fp);
144-			xmlencode(fp, name, strlen(name));
145-			fputs("</td><td>", fp);
146-			if (ci->author)
147-				printtimeshort(fp, &(ci->author->when));
148-			fputs("</td><td>", fp);
149-			if (ci->author)
150-				xmlencode(fp, ci->author->name, strlen(ci->author->name));
151-			fputs("</td></tr>\n", fp);
152+	/* sort by type, date then shorthand name */
153+	qsort(ris, refcount, sizeof(*ris), refs_cmp);
154 
155-			relpath = "../";
156+	for (i = 0, j = 0, count = 0; i < refcount; i++) {
157+		if (j == 0 && git_reference_is_tag(ris[i].ref)) {
158+			if (count)
159+				fputs("</tbody></table><br/>\n", fp);
160+			count = 0;
161+			j = 1;
162+		}
163 
164-			commitinfo_free(ci);
165-			git_object_free(obj);
166-			obj = NULL;
167-			git_reference_free(dref);
168-			dref = NULL;
169+		/* print header if it has an entry (first). */
170+		if (++count == 1) {
171+			fprintf(fp, "<h2>%s</h2><table id=\"%s\">"
172+		                "<thead>\n<tr><td><b>Name</b></td>"
173+			        "<td><b>Last commit date</b></td>"
174+			        "<td><b>Author</b></td>\n</tr>\n"
175+			        "</thead><tbody>\n",
176+			         titles[j], ids[j]);
177 		}
178-		/* table footer */
179-		if (count)
180-			fputs("</tbody></table><br/>", fp);
181+
182+		ci = ris[i].ci;
183+		s = git_reference_shorthand(ris[i].ref);
184+
185+		fputs("<tr><td>", fp);
186+		xmlencode(fp, s, strlen(s));
187+		fputs("</td><td>", fp);
188+		if (ci->author)
189+			printtimeshort(fp, &(ci->author->when));
190+		fputs("</td><td>", fp);
191+		if (ci->author)
192+			xmlencode(fp, ci->author->name, strlen(ci->author->name));
193+		fputs("</td></tr>\n", fp);
194 	}
195+	/* table footer */
196+	if (count)
197+		fputs("</tbody></table><br/>\n", fp);
198 
199 err:
200 	git_object_free(obj);
201 	git_reference_free(dref);
202 
203-	for (i = 0; i < refcount; i++)
204-		git_reference_free(refs[i]);
205-	free(refs);
206+	for (i = 0; i < refcount; i++) {
207+		commitinfo_free(ris[i].ci);
208+		git_reference_free(ris[i].ref);
209+	}
210+	free(ris);
211 
212 	return 0;
213 }