gout

A static git page generator
git clone https://git.bracken.jp/gout.git
Log | Files | Refs | README | LICENSE

commit f1a1af6c69114cc1e4d97c1681749fbb98618ad9
parent 5e07b449b19e29773d52f03c1cdb734b7a67e78e
Author: Chris Bracken <chris@bracken.jp>
Date:   Fri, 20 Feb 2026 14:47:12 +0900

Improve error handling in gitrepo_walk_tree_files

Previously, we implicitly assumed that if git_tree_entry_to_object()
failed, we were dealing with a submodule. We now explicitly check the
filemode of each entry using git_tree_entry_filemode(). If the mode is
GIT_FILEMODE_COMMIT, then we handle as a submodule immediately;
otherwise we try to resolve the object. If resolution fails, we emit a
warning.

Diffstat:
Msrc/git/git.c | 83++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
1 file changed, 46 insertions(+), 37 deletions(-)

diff --git a/src/git/git.c b/src/git/git.c @@ -336,8 +336,8 @@ static bool gitrepo_walk_tree_files(git_repository* repo, entrypath = path_concat(path, entryname); } - git_object* obj = NULL; - if (git_tree_entry_to_object(&obj, repo, entry) != 0) { + git_filemode_t mode = git_tree_entry_filemode(entry); + if (mode == GIT_FILEMODE_COMMIT) { char oid_str[GIT_OID_SHA1_HEXSIZE + 1]; git_oid_tostr(oid_str, sizeof(oid_str), git_tree_entry_id(entry)); GitFile* fileinfo = @@ -345,48 +345,57 @@ static bool gitrepo_walk_tree_files(git_repository* repo, ".gitmodules", oid_str, -1, -1, ""); cb(fileinfo, user_data); gitfile_free(fileinfo); - } else { - switch (git_object_type(obj)) { - case GIT_OBJECT_BLOB: - break; - case GIT_OBJECT_TREE: { - if (!gitrepo_walk_tree_files(repo, (git_tree*)obj, entrypath, cb, - user_data)) { - git_object_free(obj); - free(entrypath); - return false; - } + free(entrypath); + continue; + } + + git_object* obj = NULL; + if (git_tree_entry_to_object(&obj, repo, entry) != 0) { + warnx("failed to get object for tree entry: %s", entrypath); + free(entrypath); + continue; + } + + switch (git_object_type(obj)) { + case GIT_OBJECT_BLOB: + break; + case GIT_OBJECT_TREE: { + if (!gitrepo_walk_tree_files(repo, (git_tree*)obj, entrypath, cb, + user_data)) { git_object_free(obj); free(entrypath); - continue; + return false; } - default: - git_object_free(obj); - free(entrypath); - continue; + git_object_free(obj); + free(entrypath); + continue; } + default: + git_object_free(obj); + free(entrypath); + continue; + } - git_blob* blob = (git_blob*)obj; - ssize_t size_bytes = git_blob_rawsize(blob); - ssize_t size_lines = -1; - const char* content = ""; - - if (size_bytes > kMaxFileSizeBytes) { - size_lines = -2; /* oversized file */ - } else if (!git_blob_is_binary(blob)) { - content = (const char*)git_blob_rawcontent(blob); - size_lines = string_count_lines(content, size_bytes); - } + git_blob* blob = (git_blob*)obj; + ssize_t size_bytes = git_blob_rawsize(blob); + ssize_t size_lines = -1; + const char* content = ""; - char* filemode = format_filemode(git_tree_entry_filemode(entry)); - GitFile* fileinfo = - gitfile_create(kFileTypeFile, filemode, entrypath, entrypath, "", - size_bytes, size_lines, content); - cb(fileinfo, user_data); - gitfile_free(fileinfo); - git_object_free(obj); - free(filemode); + if (size_bytes > kMaxFileSizeBytes) { + size_lines = -2; /* oversized file */ + } else if (!git_blob_is_binary(blob)) { + content = (const char*)git_blob_rawcontent(blob); + size_lines = string_count_lines(content, size_bytes); } + + char* filemode = format_filemode(git_tree_entry_filemode(entry)); + GitFile* fileinfo = + gitfile_create(kFileTypeFile, filemode, entrypath, entrypath, "", + size_bytes, size_lines, content); + cb(fileinfo, user_data); + gitfile_free(fileinfo); + git_object_free(obj); + free(filemode); free(entrypath); } return true;