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:
| M | src/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;