[PATCH 1/3] show-index: implement automatic hash detection
From: Shreyansh Paliwal <hidden>
Date: 2026-01-20 14:09:55
Subsystem:
the rest · Maintainer:
Linus Torvalds
When git show-index is run outside a repository, it currently falls back to SHA-1 unless the hash algorithm is explicitly specified via --object-format. This can lead to failures when reading SHA-256 pack index files. To prevent this add an automatic hash algorithm detection, as suggested by an existing TODO comment in the code. For v2 index files, the fixed size can be computed and then, the overall file size combined with the number of objects, can be used to compute the hash size of the objects. Since SHA-1 and SHA-256 use fixed hash sizes (20 and 32 bytes, respectively), the hash algorithm can be determined. This detection is limited in scope. It only applies when the index file does not contain any 64-bit offset entries, which introduce additional variable-sized data into the file layout. When such offsets are present, automatic detection becomes irrelevant, and the user is instead required to specify the hash algorithm explicitly using --object-format. Signed-off-by: Shreyansh Paliwal <redacted> --- builtin/show-index.c | 45 +++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-)
diff --git a/builtin/show-index.c b/builtin/show-index.c
index 2c3e2940ce..be62edc57b 100644
--- a/builtin/show-index.c
+++ b/builtin/show-index.c@@ -40,17 +40,6 @@ int cmd_show_index(int argc, repo_set_hash_algo(the_repository, hash_algo); } - /* - * Fallback to SHA1 if we are running outside of a repository. - * - * TODO: Figure out and implement a way to detect the hash algorithm in use by the - * the index file passed in and use that instead. - */ - if (!the_hash_algo) - repo_set_hash_algo(the_repository, GIT_HASH_DEFAULT); - - hashsz = the_hash_algo->rawsz; - if (fread(top_index, 2 * 4, 1, stdin) != 1) die("unable to read header"); if (top_index[0] == htonl(PACK_IDX_SIGNATURE)) {
@@ -71,6 +60,40 @@ int cmd_show_index(int argc, die("corrupt index file"); nr = n; } + + /* detection of hash algorithm + Only works for small files, i.e without large offsets */ + if(!the_hash_algo && version == 2) { + struct stat st; + size_t file_base_size; + size_t table_size; + size_t size_rem; + size_t hash_size; + + if(fstat(0, &st) || !S_ISREG(st.st_mode)) + die(_("unable to detect hash from non-regular file")); + + file_base_size = 8 + (256 * 4); + table_size = file_base_size + (nr * 4 * 4); + size_rem = st.st_size - table_size; + hash_size = size_rem / (nr + 2); + + if(hash_size == GIT_SHA1_RAWSZ) { + repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + } else if(hash_size == GIT_SHA256_RAWSZ) { + repo_set_hash_algo(the_repository, GIT_HASH_SHA256); + } else { + die(_("unable to detect hash algorithm, " + "use --object-format option")); + } + } + + /* Final fallback to SHA1 */ + if(!the_hash_algo) + repo_set_hash_algo(the_repository, GIT_HASH_SHA1); + + hashsz = the_hash_algo->rawsz; + if (version == 1) { for (i = 0; i < nr; i++) { unsigned int offset, entry[(GIT_MAX_RAWSZ + 4) / sizeof(unsigned int)];
--
2.52.0