bidet

commit f827488cea1a4accd20d81647d15cd5692a71752

tree

parent:
e4c00fc2a01331bb0b70d8f881ce63a4d7dbccbf

nmyk <nick@nmyk.io>

2026-02-16T14:29:45-05:00

handle / in branch or tag name

diff --git a/main.go b/main.go
index dd2b8362d9ad56026e91aec6f22cff4c7bb00e0f..d0625a493efbdfe4acbcd61d40408adf8d9c2357 100644
--- a/main.go
+++ b/main.go
@@ -39,9 +39,8 @@ 	mux.HandleFunc("GET /", listRepos)
 	mux.HandleFunc("GET /{name}", repoIndex)
 	mux.HandleFunc("GET /{name}/refs", refs)
 	mux.HandleFunc("GET /{name}/refs/{type}", refs)
-	mux.HandleFunc("GET /{name}/tree/{ref}", repoTree)
-	mux.HandleFunc("GET /{name}/tree/{ref}/{path...}", repoTree)
-	mux.HandleFunc("GET /{name}/blob/{ref}/{path...}", blob)
+	mux.HandleFunc("GET /{name}/tree/{path...}", repoTree)
+	mux.HandleFunc("GET /{name}/blob/{path...}", blob)
 	return mux
 }
 
@@ -159,6 +158,29 @@ 	}
 	serve(w, "refs", data)
 }
 
+func parse(repo *git.Repository, refAndPath string) (refName string, urlPath string) {
+	if refAndPath == "" {
+		return "", ""
+	}
+	candidate := strings.TrimPrefix(refAndPath, "/")
+	for {
+		ref, err := resolve(repo, candidate)
+		if err == nil {
+			if len(candidate) < len(refAndPath) {
+				urlPath = strings.TrimPrefix(refAndPath[len(candidate):], "/")
+			}
+			refName = ref.Name().Short()
+			return
+		}
+		parent := path.Dir(candidate)
+		if parent == "." || parent == candidate {
+			break
+		}
+		candidate = parent
+	}
+	return "", ""
+}
+
 func blob(w http.ResponseWriter, r *http.Request) {
 	repoName := r.PathValue("name")
 	if _, err := os.Stat(repoName + DOT_GIT); os.IsNotExist(err) {
@@ -170,7 +192,7 @@ 	if err != nil {
 		http.Error(w, err.Error(), 500)
 		return
 	}
-	refName := r.PathValue("ref")
+	refName, filePath := parse(repo, r.PathValue("path"))
 	ref, err := resolve(repo, refName)
 	if err != nil {
 		http.NotFound(w, r)
@@ -186,7 +208,6 @@ 	if err != nil {
 		http.Error(w, err.Error(), 500)
 		return
 	}
-	filePath := r.PathValue("path")
 	entry, err := tree.FindEntry(filePath)
 	if err != nil {
 		http.NotFound(w, nil)
@@ -262,13 +283,12 @@ 	if err != nil {
 		http.Error(w, err.Error(), 500)
 		return
 	}
-	refName := r.PathValue("ref")
+	refName, treePath := parse(repo, r.PathValue("path"))
 	head, err := repo.Head()
 	if err != nil {
 		http.Error(w, "Cannot resolve HEAD state", 500)
 	}
 	headRef := head.Name().Short()
-	treePath := r.PathValue("path")
 	if refName == headRef && treePath == "" {
 		repoIndex(w, r)
 		return