Merge branch 'jt/index-fd-wo-repo-regression-fix-maint'

During Git 2.52 timeframe, we broke streaming computation of object
hash outside a repository, which has been corrected.

* jt/index-fd-wo-repo-regression-fix-maint:
  object-file: avoid ODB transaction when not writing objects
maint
Junio C Hamano 2026-04-08 10:20:51 -07:00
commit fe4ab2e698
2 changed files with 52 additions and 11 deletions

View File

@ -1642,6 +1642,34 @@ static int index_blob_packfile_transaction(struct odb_transaction_files *transac
return 0;
}

static int hash_blob_stream(const struct git_hash_algo *hash_algo,
struct object_id *result_oid, int fd, size_t size)
{
unsigned char buf[16384];
struct git_hash_ctx ctx;
unsigned header_len;

header_len = format_object_header((char *)buf, sizeof(buf),
OBJ_BLOB, size);
hash_algo->init_fn(&ctx);
git_hash_update(&ctx, buf, header_len);

while (size) {
size_t rsize = size < sizeof(buf) ? size : sizeof(buf);
ssize_t read_result = read_in_full(fd, buf, rsize);

if ((read_result < 0) || ((size_t)read_result != rsize))
return -1;

git_hash_update(&ctx, buf, rsize);
size -= read_result;
}

git_hash_final_oid(result_oid, &ctx);

return 0;
}

int index_fd(struct index_state *istate, struct object_id *oid,
int fd, struct stat *st,
enum object_type type, const char *path, unsigned flags)
@ -1663,6 +1691,7 @@ int index_fd(struct index_state *istate, struct object_id *oid,
ret = index_core(istate, oid, fd, xsize_t(st->st_size),
type, path, flags);
} else {
if (flags & INDEX_WRITE_OBJECT) {
struct object_database *odb = the_repository->objects;
struct odb_transaction_files *files_transaction;
struct odb_transaction *transaction;
@ -1675,6 +1704,10 @@ int index_fd(struct index_state *istate, struct object_id *oid,
xsize_t(st->st_size),
path, flags);
odb_transaction_commit(transaction);
} else {
ret = hash_blob_stream(the_repository->hash_algo, oid,
fd, xsize_t(st->st_size));
}
}

close(fd);

View File

@ -93,6 +93,14 @@ test_expect_success 'diff outside repository' '
test_cmp expect actual
'

test_expect_success 'hash object exceeding bigFileThreshold outside repository' '
(
cd non-repo &&
echo foo >foo &&
git -c core.bigFileThreshold=1 hash-object --stdin <foo
)
'

test_expect_success 'stripspace outside repository' '
nongit git stripspace -s </dev/null
'