aboutsummaryrefslogtreecommitdiff
path: root/refstore/shorten.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-02-21 11:33:40 +0800
committerGravatar Runxi Yu2026-02-21 11:33:40 +0800
commit6cdf75c5a9e1f660aa2a86938be680c5db07ffd2 (patch)
treef16f22cc51930e97eaeb73e1e436d8a4c331fabf /refstore/shorten.go
parentrefstore/loose: Add loose refs implementation (diff)
signatureNo signature
refstore: Add ref shortening
Diffstat (limited to 'refstore/shorten.go')
-rw-r--r--refstore/shorten.go74
1 files changed, 74 insertions, 0 deletions
diff --git a/refstore/shorten.go b/refstore/shorten.go
new file mode 100644
index 00000000..26fa82c0
--- /dev/null
+++ b/refstore/shorten.go
@@ -0,0 +1,74 @@
+package refstore
+
+import "strings"
+
+type shortenRule struct {
+ prefix string
+ suffix string
+}
+
+var shortenRules = [...]shortenRule{
+ {prefix: "", suffix: ""},
+ {prefix: "refs/", suffix: ""},
+ {prefix: "refs/tags/", suffix: ""},
+ {prefix: "refs/heads/", suffix: ""},
+ {prefix: "refs/remotes/", suffix: ""},
+ {prefix: "refs/remotes/", suffix: "/HEAD"},
+}
+
+func (rule shortenRule) match(name string) (string, bool) {
+ if !strings.HasPrefix(name, rule.prefix) {
+ return "", false
+ }
+ if !strings.HasSuffix(name, rule.suffix) {
+ return "", false
+ }
+ short := strings.TrimPrefix(name, rule.prefix)
+ short = strings.TrimSuffix(short, rule.suffix)
+ if short == "" {
+ return "", false
+ }
+ if rule.prefix+short+rule.suffix != name {
+ return "", false
+ }
+ return short, true
+}
+
+func (rule shortenRule) render(short string) string {
+ return rule.prefix + short + rule.suffix
+}
+
+// ShortenName returns the shortest unambiguous shorthand for name among all.
+//
+// all must contain full reference names visible to the shortening scope.
+func ShortenName(name string, all []string) string {
+ names := make(map[string]struct{}, len(all))
+ for _, full := range all {
+ if full == "" {
+ continue
+ }
+ names[full] = struct{}{}
+ }
+
+ for i := len(shortenRules) - 1; i > 0; i-- {
+ short, ok := shortenRules[i].match(name)
+ if !ok {
+ continue
+ }
+ ambiguous := false
+ for j := range shortenRules {
+ if j == i {
+ continue
+ }
+ full := shortenRules[j].render(short)
+ if _, found := names[full]; found {
+ ambiguous = true
+ break
+ }
+ }
+ if !ambiguous {
+ return short
+ }
+ }
+ return name
+}