aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2026-04-08 10:20:51 -0700
committerJunio C Hamano <gitster@pobox.com>2026-04-08 10:20:51 -0700
commitfe4ab2e698d544a082862a14120efc6b49047382 (patch)
tree522c42678b395b3a106b6ae744ed50ba2d9d51ed
parent37a4780f2c30de9fe0bef533a266c6bca767a50f (diff)
parent7d8727ff0b621a9729c2de6a3698063b7b3ba2d6 (diff)
downloadgit-fe4ab2e698d544a082862a14120efc6b49047382.tar.xz
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
-rw-r--r--object-file.c55
-rwxr-xr-xt/t1517-outside-repo.sh8
2 files changed, 52 insertions, 11 deletions
diff --git a/object-file.c b/object-file.c
index c353176206..2acc9522df 100644
--- a/object-file.c
+++ b/object-file.c
@@ -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,18 +1691,23 @@ 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 {
- struct object_database *odb = the_repository->objects;
- struct odb_transaction_files *files_transaction;
- struct odb_transaction *transaction;
+ if (flags & INDEX_WRITE_OBJECT) {
+ struct object_database *odb = the_repository->objects;
+ struct odb_transaction_files *files_transaction;
+ struct odb_transaction *transaction;
- transaction = odb_transaction_begin(odb);
- files_transaction = container_of(odb->transaction,
- struct odb_transaction_files,
- base);
- ret = index_blob_packfile_transaction(files_transaction, oid, fd,
- xsize_t(st->st_size),
- path, flags);
- odb_transaction_commit(transaction);
+ transaction = odb_transaction_begin(odb);
+ files_transaction = container_of(odb->transaction,
+ struct odb_transaction_files,
+ base);
+ ret = index_blob_packfile_transaction(files_transaction, oid, fd,
+ 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);
diff --git a/t/t1517-outside-repo.sh b/t/t1517-outside-repo.sh
index c824c1a25c..e1d35170de 100755
--- a/t/t1517-outside-repo.sh
+++ b/t/t1517-outside-repo.sh
@@ -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
'