make get_short_ref a public function
Often we want to shorten a full ref name to something "prettier" to show a user. For example, "refs/heads/master" is often shown simply as "master", or "refs/remotes/origin/master" is shown as "origin/master". Many places in the code use a very simple formula: skip common prefixes like refs/heads, refs/remotes, etc. This is codified in the prettify_ref function. for-each-ref has a more correct (but more expensive) approach: consider the ref lookup rules, and try shortening as much as possible while remaining unambiguous. This patch makes the latter strategy globally available as shorten_unambiguous_ref. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff King committed
Apr 7, 2009 at 03:14 UTC
7c2b3029df45a74d0ebd11afcc94259791cfb90d
3 files changed
+101
-104
builtin-for-each-ref.c
+1
-104
@@ -545,109 +545,6 @@ static void grab_values(struct atom_value *val, int deref, struct object *obj, v
545
}
546
}
547
548
-/*
549
- * generate a format suitable for scanf from a ref_rev_parse_rules
550
- * rule, that is replace the "%.*s" spec with a "%s" spec
551
- */
552
-static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
553
-{
554
- char *spec;
555
-
556
- spec = strstr(rule, "%.*s");
557
- if (!spec || strstr(spec + 4, "%.*s"))
558
- die("invalid rule in ref_rev_parse_rules: %s", rule);
559
-
560
- /* copy all until spec */
561
- strncpy(scanf_fmt, rule, spec - rule);
562
- scanf_fmt[spec - rule] = '\0';
563
- /* copy new spec */
564
- strcat(scanf_fmt, "%s");
565
- /* copy remaining rule */
566
- strcat(scanf_fmt, spec + 4);
567
-
568
- return;
569
-}
570
-
571
-/*
572
- * Shorten the refname to an non-ambiguous form
573
- */
574
-static char *get_short_ref(const char *ref)
575
-{
576
- int i;
577
- static char **scanf_fmts;
578
- static int nr_rules;
579
- char *short_name;
580
-
581
- /* pre generate scanf formats from ref_rev_parse_rules[] */
582
- if (!nr_rules) {
583
- size_t total_len = 0;
584
-
585
- /* the rule list is NULL terminated, count them first */
586
- for (; ref_rev_parse_rules[nr_rules]; nr_rules++)
587
- /* no +1 because strlen("%s") < strlen("%.*s") */
588
- total_len += strlen(ref_rev_parse_rules[nr_rules]);
589
-
590
- scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);
591
-
592
- total_len = 0;
593
- for (i = 0; i < nr_rules; i++) {
594
- scanf_fmts[i] = (char *)&scanf_fmts[nr_rules]
595
- + total_len;
596
- gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]);
597
- total_len += strlen(ref_rev_parse_rules[i]);
598
- }
599
- }
600
-
601
- /* bail out if there are no rules */
602
- if (!nr_rules)
603
- return xstrdup(ref);
604
-
605
- /* buffer for scanf result, at most ref must fit */
606
- short_name = xstrdup(ref);
607
-
608
- /* skip first rule, it will always match */
609
- for (i = nr_rules - 1; i > 0 ; --i) {
610
- int j;
611
- int short_name_len;
612
-
613
- if (1 != sscanf(ref, scanf_fmts[i], short_name))
614
- continue;
615
-
616
- short_name_len = strlen(short_name);
617
-
618
- /*
619
- * check if the short name resolves to a valid ref,
620
- * but use only rules prior to the matched one
621
- */
622
- for (j = 0; j < i; j++) {
623
- const char *rule = ref_rev_parse_rules[j];
624
- unsigned char short_objectname[20];
625
- char refname[PATH_MAX];
626
-
627
- /*
628
- * the short name is ambiguous, if it resolves
629
- * (with this previous rule) to a valid ref
630
- * read_ref() returns 0 on success
631
- */
632
- mksnpath(refname, sizeof(refname),
633
- rule, short_name_len, short_name);
634
- if (!read_ref(refname, short_objectname))
635
- break;
636
- }
637
-
638
- /*
639
- * short name is non-ambiguous if all previous rules
640
- * haven't resolved to a valid ref
641
- */
642
- if (j == i)
643
- return short_name;
644
- }
645
-
646
- free(short_name);
647
- return xstrdup(ref);
648
-}
649
-
650
-
548
/*
549
* Parse the object referred by ref, and grab needed value.
550
*/
@@ -704,7 +601,7 @@ static void populate_value(struct refinfo *ref)
601
if (formatp) {
602
formatp++;
603
if (!strcmp(formatp, "short"))
707
- refname = get_short_ref(refname);
604
+ refname = shorten_unambiguous_ref(refname);
605
else
606
die("unknown %.*s format %s",
607
(int)(formatp - name), name, formatp);
refs.c
+99
@@ -1652,3 +1652,102 @@ struct ref *find_ref_by_name(const struct ref *list, const char *name)
1652
return (struct ref *)list;
1653
return NULL;
1654
}
1655
+
1656
+/*
1657
+ * generate a format suitable for scanf from a ref_rev_parse_rules
1658
+ * rule, that is replace the "%.*s" spec with a "%s" spec
1659
+ */
1660
+static void gen_scanf_fmt(char *scanf_fmt, const char *rule)
1661
+{
1662
+ char *spec;
1663
+
1664
+ spec = strstr(rule, "%.*s");
1665
+ if (!spec || strstr(spec + 4, "%.*s"))
1666
+ die("invalid rule in ref_rev_parse_rules: %s", rule);
1667
+
1668
+ /* copy all until spec */
1669
+ strncpy(scanf_fmt, rule, spec - rule);
1670
+ scanf_fmt[spec - rule] = '\0';
1671
+ /* copy new spec */
1672
+ strcat(scanf_fmt, "%s");
1673
+ /* copy remaining rule */
1674
+ strcat(scanf_fmt, spec + 4);
1675
+
1676
+ return;
1677
+}
1678
+
1679
+char *shorten_unambiguous_ref(const char *ref)
1680
+{
1681
+ int i;
1682
+ static char **scanf_fmts;
1683
+ static int nr_rules;
1684
+ char *short_name;
1685
+
1686
+ /* pre generate scanf formats from ref_rev_parse_rules[] */
1687
+ if (!nr_rules) {
1688
+ size_t total_len = 0;
1689
+
1690
+ /* the rule list is NULL terminated, count them first */
1691
+ for (; ref_rev_parse_rules[nr_rules]; nr_rules++)
1692
+ /* no +1 because strlen("%s") < strlen("%.*s") */
1693
+ total_len += strlen(ref_rev_parse_rules[nr_rules]);
1694
+
1695
+ scanf_fmts = xmalloc(nr_rules * sizeof(char *) + total_len);
1696
+
1697
+ total_len = 0;
1698
+ for (i = 0; i < nr_rules; i++) {
1699
+ scanf_fmts[i] = (char *)&scanf_fmts[nr_rules]
1700
+ + total_len;
1701
+ gen_scanf_fmt(scanf_fmts[i], ref_rev_parse_rules[i]);
1702
+ total_len += strlen(ref_rev_parse_rules[i]);
1703
+ }
1704
+ }
1705
+
1706
+ /* bail out if there are no rules */
1707
+ if (!nr_rules)
1708
+ return xstrdup(ref);
1709
+
1710
+ /* buffer for scanf result, at most ref must fit */
1711
+ short_name = xstrdup(ref);
1712
+
1713
+ /* skip first rule, it will always match */
1714
+ for (i = nr_rules - 1; i > 0 ; --i) {
1715
+ int j;
1716
+ int short_name_len;
1717
+
1718
+ if (1 != sscanf(ref, scanf_fmts[i], short_name))
1719
+ continue;
1720
+
1721
+ short_name_len = strlen(short_name);
1722
+
1723
+ /*
1724
+ * check if the short name resolves to a valid ref,
1725
+ * but use only rules prior to the matched one
1726
+ */
1727
+ for (j = 0; j < i; j++) {
1728
+ const char *rule = ref_rev_parse_rules[j];
1729
+ unsigned char short_objectname[20];
1730
+ char refname[PATH_MAX];
1731
+
1732
+ /*
1733
+ * the short name is ambiguous, if it resolves
1734
+ * (with this previous rule) to a valid ref
1735
+ * read_ref() returns 0 on success
1736
+ */
1737
+ mksnpath(refname, sizeof(refname),
1738
+ rule, short_name_len, short_name);
1739
+ if (!read_ref(refname, short_objectname))
1740
+ break;
1741
+ }
1742
+
1743
+ /*
1744
+ * short name is non-ambiguous if all previous rules
1745
+ * haven't resolved to a valid ref
1746
+ */
1747
+ if (j == i)
1748
+ return short_name;
1749
+ }
1750
+
1751
+ free(short_name);
1752
+ return xstrdup(ref);
1753
+}
refs.h
+1
@@ -80,6 +80,7 @@ extern int for_each_reflog(each_ref_fn, void *);
80
extern int check_ref_format(const char *target);
81
82
extern const char *prettify_ref(const struct ref *ref);
83
+extern char *shorten_unambiguous_ref(const char *ref);
84
85
/** rename ref, return 0 on success **/
86
extern int rename_ref(const char *oldref, const char *newref, const char *logmsg);