From 09a5334f28c853530ab6a70e11929e9a0f2aca45 Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Thu, 1 Oct 2026 17:27:43 -1000 Subject: Walk a path on the blob page from any commit the id names With both an id and a path the blob page handed back the raw object the id named, so a commit id gave the commit text itself, while the plain page looked the path up in that commit's tree. A tag is peeled to its commit on the way, and the README example of a pinned commit now uses a form the request checks accept. --- README.txt | 2 +- source/ui-blob.c | 20 +++++++++++++------- tests/t0303-robustness.sh | 15 +++++++++++++++ 3 files changed, 29 insertions(+), 8 deletions(-) diff --git a/README.txt b/README.txt index 5582164..d2eefea 100644 --- a/README.txt +++ b/README.txt @@ -192,7 +192,7 @@ Some worked examples, in the url= form. ?url=demo/log&h=next log of the next branch ?url=demo/log&qt=author&q=alice commits authored by alice ?url=demo/tree/src&h=v1.0 the src directory at tag v1.0 - ?url=demo/commit&id=HEAD~3 one commit, pinned + ?url=demo/commit&id=v1.0 one commit, pinned to a tag ?url=demo/diff&id=main&id2=next diff between two branches ?url=demo/plain/README.md the raw bytes of one file ?url=demo/atom&h=main the commit feed for a branch diff --git a/source/ui-blob.c b/source/ui-blob.c index 8407342..4105e48 100644 --- a/source/ui-blob.c +++ b/source/ui-blob.c @@ -181,17 +181,23 @@ void cgit_print_blob(const char *hex, char *path, const char *head, int file_onl cgit_print_error_page(404, "Not Found", "Bad object id: %s", hex); return; } - } else { - if (repo_get_oid(the_repository, head, &oid)) { - cgit_print_error_page(404, "Not Found", "Bad object id: %s", head); - return; - } - peel_to_commit(&oid); + } else if (repo_get_oid(the_repository, head, &oid)) { + cgit_print_error_page(404, "Not Found", "Bad object id: %s", head); + return; } type = odb_read_object_info(the_repository->objects, &oid, &size); - if (!hex && type == OBJ_COMMIT && path) { + // A tag is peeled to its commit, so a path can be looked up in the + // tree whether the id or the head named the tag. The type is read + // first because peeling a blob would read it whole just to learn that + // it is one. + if (type == OBJ_TAG) { + peel_to_commit(&oid); + type = odb_read_object_info(the_repository->objects, &oid, &size); + } + + if (type == OBJ_COMMIT && path) { if (!find_path_oid(&oid, path, file_only)) { cgit_print_error_page(404, "Not Found", "Path not found: %s", path); return; diff --git a/tests/t0303-robustness.sh b/tests/t0303-robustness.sh index 73c2ca5..5bdb060 100755 --- a/tests/t0303-robustness.sh +++ b/tests/t0303-robustness.sh @@ -246,6 +246,21 @@ test_expect_success 'the blob page reads a file through an annotated tag' ' test_cmp want body ' +# The plain page walks a path out of whatever commit the id names, and the +# blob page used to answer such a request with the raw commit object. +test_expect_success 'the blob page walks a path out of the commit or tag the id names' ' + tip=$(git -C repos/rob rev-parse HEAD) && + robq "url=rob/blob/file-1&id=$tip" >tmp && + strip_headers body && + test_cmp want body && + tag=$(git -C repos/rob rev-parse ann) && + robq "url=rob/blob/file-1&id=$tag" >tmp && + strip_headers body && + test_cmp want body && + robq "url=rob/blob/missing&id=$tip" >tmp && + grep "^Status: 404" tmp +' + test_expect_success 'the commit page shows a message whole when text follows its trailers' ' ( cd repos/rob && -- cgit v2.8.0