@@ -13,16 +13,55 @@ typedef struct rev_name {
1313 unsigned long taggerdate ;
1414 int generation ;
1515 int distance ;
16+ int from_tag ;
1617} rev_name ;
1718
1819static long cutoff = LONG_MAX ;
1920
2021/* How many generations are maximally preferred over _one_ merge traversal? */
2122#define MERGE_TRAVERSAL_WEIGHT 65535
2223
24+ static int is_better_name (struct rev_name * name ,
25+ const char * tip_name ,
26+ unsigned long taggerdate ,
27+ int generation ,
28+ int distance ,
29+ int from_tag )
30+ {
31+ /*
32+ * When comparing names based on tags, prefer names
33+ * based on the older tag, even if it is farther away.
34+ */
35+ if (from_tag && name -> from_tag )
36+ return (name -> taggerdate > taggerdate ||
37+ (name -> taggerdate == taggerdate &&
38+ name -> distance > distance ));
39+
40+ /*
41+ * We know that at least one of them is a non-tag at this point.
42+ * favor a tag over a non-tag.
43+ */
44+ if (name -> from_tag != from_tag )
45+ return from_tag ;
46+
47+ /*
48+ * We are now looking at two non-tags. Tiebreak to favor
49+ * shorter hops.
50+ */
51+ if (name -> distance != distance )
52+ return name -> distance > distance ;
53+
54+ /* ... or tiebreak to favor older date */
55+ if (name -> taggerdate != taggerdate )
56+ return name -> taggerdate > taggerdate ;
57+
58+ /* keep the current one if we cannot decide */
59+ return 0 ;
60+ }
61+
2362static void name_rev (struct commit * commit ,
2463 const char * tip_name , unsigned long taggerdate ,
25- int generation , int distance ,
64+ int generation , int distance , int from_tag ,
2665 int deref )
2766{
2867 struct rev_name * name = (struct rev_name * )commit -> util ;
@@ -46,14 +85,14 @@ static void name_rev(struct commit *commit,
4685 name = xmalloc (sizeof (rev_name ));
4786 commit -> util = name ;
4887 goto copy_data ;
49- } else if (name -> taggerdate > taggerdate ||
50- (name -> taggerdate == taggerdate &&
51- name -> distance > distance )) {
88+ } else if (is_better_name (name , tip_name , taggerdate ,
89+ generation , distance , from_tag )) {
5290copy_data :
5391 name -> tip_name = tip_name ;
5492 name -> taggerdate = taggerdate ;
5593 name -> generation = generation ;
5694 name -> distance = distance ;
95+ name -> from_tag = from_tag ;
5796 } else {
5897 free (to_free );
5998 return ;
@@ -75,10 +114,12 @@ static void name_rev(struct commit *commit,
75114 parent_number );
76115
77116 name_rev (parents -> item , new_name , taggerdate , 0 ,
78- distance + MERGE_TRAVERSAL_WEIGHT , 0 );
117+ distance + MERGE_TRAVERSAL_WEIGHT ,
118+ from_tag , 0 );
79119 } else {
80120 name_rev (parents -> item , tip_name , taggerdate ,
81- generation + 1 , distance + 1 , 0 );
121+ generation + 1 , distance + 1 ,
122+ from_tag , 0 );
82123 }
83124 }
84125}
@@ -209,9 +250,13 @@ static int name_ref(const char *path, const struct object_id *oid, int flags, vo
209250 }
210251 if (o && o -> type == OBJ_COMMIT ) {
211252 struct commit * commit = (struct commit * )o ;
253+ int from_tag = starts_with (path , "refs/tags/" );
212254
255+ if (taggerdate == ULONG_MAX )
256+ taggerdate = ((struct commit * )o )-> date ;
213257 path = name_ref_abbrev (path , can_abbreviate_output );
214- name_rev (commit , xstrdup (path ), taggerdate , 0 , 0 , deref );
258+ name_rev (commit , xstrdup (path ), taggerdate , 0 , 0 ,
259+ from_tag , deref );
215260 }
216261 return 0 ;
217262}
0 commit comments