From 2e60aabc759e3467e21a98f4e739c5e9f221cd9f Mon Sep 17 00:00:00 2001 From: Alex Mironov Date: Wed, 21 May 2025 21:29:31 +0000 Subject: [PATCH 01/21] name-hash: don't add sparse directories in threaded lazy init Ensure that logic added in 5f11669586 (name-hash: don't add directories to name_hash, 2021-04-12) also applies in multithreaded hashtable init path. As per the original single-threaded change above: sparse directory entries represent a directory that is outside the sparse-checkout definition. These are not paths to blobs, so should not be added to the name_hash table. Instead, they should be added to the directory hashtable when 'ignore_case' is true. Add a condition to avoid placing sparse directories into the name_hash hashtable. This avoids filling the table with extra entries that will never be queried. Signed-off-by: Alex Mironov Signed-off-by: Junio C Hamano --- name-hash.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/name-hash.c b/name-hash.c index d66de1cdfd5633..b91e276267891e 100644 --- a/name-hash.c +++ b/name-hash.c @@ -492,8 +492,10 @@ static void *lazy_name_thread_proc(void *_data) for (k = 0; k < d->istate->cache_nr; k++) { struct cache_entry *ce_k = d->istate->cache[k]; ce_k->ce_flags |= CE_HASHED; - hashmap_entry_init(&ce_k->ent, d->lazy_entries[k].hash_name); - hashmap_add(&d->istate->name_hash, &ce_k->ent); + if (!S_ISSPARSEDIR(ce_k->ce_mode)) { + hashmap_entry_init(&ce_k->ent, d->lazy_entries[k].hash_name); + hashmap_add(&d->istate->name_hash, &ce_k->ent); + } } return NULL; From b103881d4f4b157d86813ba5f91acd7ed6c888d0 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Thu, 22 May 2025 16:55:20 +0100 Subject: [PATCH 02/21] midx repack: avoid integer overflow on 32 bit systems On a 32 bit system "git multi-pack-index --repack --batch-size=120M" failed with fatal: size_t overflow: 6038786 * 1289 The calculation to estimated size of the objects in the pack referenced by the multi-pack-index uses st_mult() to multiply the pack size by the number of referenced objects before dividing by the total number of objects in the pack. As size_t is 32 bits on 32 bit systems this calculation easily overflows. Fix this by using 64bit arithmetic instead. Also fix a potential overflow when caluculating the total size of the objects referenced by the multipack index with a batch size larger than SIZE_MAX / 2. In that case total_size += estimated_size can overflow as both total_size and estimated_size can be greater that SIZE_MAX / 2. This is addressed by using saturating arithmetic for the addition. Although estimated_size is of type uint64_t by the time we reach this sum it is bounded by the batch size which is of type size_t and so casting estimated_size to size_t does not truncate the value. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- git-compat-util.h | 16 ++++++++++++++++ midx-write.c | 12 ++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/git-compat-util.h b/git-compat-util.h index 36b9577c8d4b3b..4678e21c4cb80b 100644 --- a/git-compat-util.h +++ b/git-compat-util.h @@ -668,6 +668,22 @@ static inline int cast_size_t_to_int(size_t a) return (int)a; } +static inline uint64_t u64_mult(uint64_t a, uint64_t b) +{ + if (unsigned_mult_overflows(a, b)) + die("uint64_t overflow: %"PRIuMAX" * %"PRIuMAX, + (uintmax_t)a, (uintmax_t)b); + return a * b; +} + +static inline uint64_t u64_add(uint64_t a, uint64_t b) +{ + if (unsigned_add_overflows(a, b)) + die("uint64_t overflow: %"PRIuMAX" + %"PRIuMAX, + (uintmax_t)a, (uintmax_t)b); + return a + b; +} + /* * Limit size of IO chunks, because huge chunks only cause pain. OS X * 64-bit is buggy, returning EINVAL if len >= INT_MAX; and even in diff --git a/midx-write.c b/midx-write.c index dd3b3070e55dfc..105014a2792266 100644 --- a/midx-write.c +++ b/midx-write.c @@ -1699,19 +1699,23 @@ static void fill_included_packs_batch(struct repository *r, for (i = 0; total_size < batch_size && i < m->num_packs; i++) { int pack_int_id = pack_info[i].pack_int_id; struct packed_git *p = m->packs[pack_int_id]; - size_t expected_size; + uint64_t expected_size; if (!want_included_pack(r, m, pack_kept_objects, pack_int_id)) continue; - expected_size = st_mult(p->pack_size, - pack_info[i].referenced_objects); + expected_size = uint64_mult(p->pack_size, + pack_info[i].referenced_objects); expected_size /= p->num_objects; if (expected_size >= batch_size) continue; - total_size += expected_size; + if (unsigned_add_overflows(total_size, (size_t)expected_size)) + total_size = SIZE_MAX; + else + total_size += expected_size; + include_pack[pack_int_id] = 1; } From f874c0ed90c63276e0ebc445ad6fee5dcbfacb86 Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Thu, 22 May 2025 16:55:21 +0100 Subject: [PATCH 03/21] midx repack: avoid potential integer overflow on 64 bit systems On a 64 bit system the calculation p->pack_size * pack_info[i].referenced_objects could overflow. If a pack file contains 2^28 objects with an average compressed size of 1KB then the pack size will be 2^38B. If all of the objects are referenced by the multi-pack index the sum above will overflow. Avoid this by using shifted integer arithmetic and changing the order of the calculation so that the pack size is divided by the total number of objects in the pack before multiplying by the number of objects referenced by the multi-pack index. Using a shift of 14 bits should give reasonable accuracy while avoiding overflow for pack sizes less that 1PB. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- midx-write.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/midx-write.c b/midx-write.c index 105014a2792266..8121e96f4fda00 100644 --- a/midx-write.c +++ b/midx-write.c @@ -1704,9 +1704,15 @@ static void fill_included_packs_batch(struct repository *r, if (!want_included_pack(r, m, pack_kept_objects, pack_int_id)) continue; - expected_size = uint64_mult(p->pack_size, - pack_info[i].referenced_objects); + /* + * Use shifted integer arithmetic to calculate the + * expected pack size to ~4 significant digits without + * overflow for packsizes less that 1PB. + */ + expected_size = (uint64_t)pack_info[i].referenced_objects << 14; expected_size /= p->num_objects; + expected_size = u64_mult(expected_size, p->pack_size); + expected_size = u64_add(expected_size, 1u << 13) >> 14; if (expected_size >= batch_size) continue; From 3aa98a61da6e1403081b4dfaa0c644614d228bac Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Thu, 22 May 2025 16:55:22 +0100 Subject: [PATCH 04/21] midx: avoid negative array index nth_midxed_pack_int_id() returns the index of the pack file in the multi pack index's list of packfiles that the specified object. The index is returned as a uint32_t. Storing this in an int will make the index negative if the most significant bit is set. Fix this by using uint32_t as the rest of the code does. This is unlikely to be a practical problem as it requires the multipack index to reference 2^31 packfiles. Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- midx-write.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/midx-write.c b/midx-write.c index 8121e96f4fda00..ba4a94950a8314 100644 --- a/midx-write.c +++ b/midx-write.c @@ -1566,7 +1566,7 @@ int expire_midx_packs(struct repository *r, const char *object_dir, unsigned fla _("Counting referenced objects"), m->num_objects); for (i = 0; i < m->num_objects; i++) { - int pack_int_id = nth_midxed_pack_int_id(m, i); + uint32_t pack_int_id = nth_midxed_pack_int_id(m, i); count[pack_int_id]++; display_progress(progress, i + 1); } @@ -1697,7 +1697,7 @@ static void fill_included_packs_batch(struct repository *r, total_size = 0; for (i = 0; total_size < batch_size && i < m->num_packs; i++) { - int pack_int_id = pack_info[i].pack_int_id; + uint32_t pack_int_id = pack_info[i].pack_int_id; struct packed_git *p = m->packs[pack_int_id]; uint64_t expected_size; From 70b128c57635183761df8a52a56f43dc30468ded Mon Sep 17 00:00:00 2001 From: Phillip Wood Date: Thu, 22 May 2025 16:55:23 +0100 Subject: [PATCH 05/21] midx docs: clarify tie breaking Clarify what happens when an object exists in more than one pack, but not in the preferred pack. "git multi-pack-index repack" relies on ties for objects that are not in the preferred pack being resolved in favor of the newest pack that contains a copy of the object. If ties were resolved in favor of the oldest pack as the current documentation suggests the multi-pack index would not reference any of the objects in the pack created by "git multi-pack-index repack". Helped-by: Taylor Blau Signed-off-by: Phillip Wood Signed-off-by: Junio C Hamano --- Documentation/git-multi-pack-index.adoc | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Documentation/git-multi-pack-index.adoc b/Documentation/git-multi-pack-index.adoc index 631d5c7d15c0de..b6cd0d7f855d5f 100644 --- a/Documentation/git-multi-pack-index.adoc +++ b/Documentation/git-multi-pack-index.adoc @@ -38,10 +38,13 @@ write:: + -- --preferred-pack=:: - Optionally specify the tie-breaking pack used when - multiple packs contain the same object. `` must - contain at least one object. If not given, ties are - broken in favor of the pack with the lowest mtime. + When specified, break ties in favor of this pack when + there are additional copies of its objects in other + packs. Ties for objects not found in the preferred + pack are always resolved in favor of the copy in the + pack with the highest mtime. If unspecified, the pack + with the lowest mtime is used by default. The + preferred pack must have at least one object. --[no-]bitmap:: Control whether or not a multi-pack bitmap is written. From 2cc8c17d67265f1912b79f8e57fc2718597ca686 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Fri, 23 May 2025 23:40:45 -0400 Subject: [PATCH 06/21] t4129: test that git apply warns for unexpected mode changes There is no test covering what commit 01aff0a (apply: correctly reverse patch's pre- and post-image mode bits, 2023-12-26) addressed. Prior to that commit, git apply was erroneously unaware of a file's expected mode while reverse-patching a file whose mode was not changing. Add the missing test coverage to assure that git apply is aware of the expected mode of a file being patched when the patch does not indicate that the file's mode is changing. This is achieved by arranging a file mode so that it doesn't agree with patch being applied, and checking git apply's output for the warning it's supposed to raise in this situation. Test in both reverse and normal (forward) directions. Signed-off-by: Mark Mentovai Signed-off-by: Junio C Hamano --- t/t4129-apply-samemode.sh | 70 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 65 insertions(+), 5 deletions(-) diff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh index 2149ad5da44cde..bf4e7609dc335b 100755 --- a/t/t4129-apply-samemode.sh +++ b/t/t4129-apply-samemode.sh @@ -102,15 +102,23 @@ test_expect_success POSIXPERM 'do not use core.sharedRepository for working tree ) ' +test_file_mode_staged () { + git ls-files --stage -- "$2" >ls-files-output && + test_grep "^$1 " ls-files-output +} + +test_file_mode_HEAD () { + git ls-tree HEAD -- "$2" >ls-tree-output && + test_grep "^$1 " ls-tree-output +} + test_expect_success 'git apply respects core.fileMode' ' test_config core.fileMode false && echo true >script.sh && git add --chmod=+x script.sh && - git ls-files -s script.sh >ls-files-output && - test_grep "^100755" ls-files-output && + test_file_mode_staged 100755 script.sh && test_tick && git commit -m "Add script" && - git ls-tree -r HEAD script.sh >ls-tree-output && - test_grep "^100755" ls-tree-output && + test_file_mode_HEAD 100755 script.sh && echo true >>script.sh && test_tick && git commit -m "Modify script" script.sh && @@ -126,7 +134,59 @@ test_expect_success 'git apply respects core.fileMode' ' test_grep ! "has type 100644, expected 100755" err && git apply --cached patch 2>err && - test_grep ! "has type 100644, expected 100755" err + test_grep ! "has type 100644, expected 100755" err && + git reset --hard +' + +test_expect_success 'setup: git apply [--reverse] warns about incorrect file modes' ' + test_config core.fileMode false && + + >mode_test && + git add --chmod=-x mode_test && + test_file_mode_staged 100644 mode_test && + test_tick && git commit -m "add mode_test" && + test_file_mode_HEAD 100644 mode_test && + git tag mode_test_forward_initial && + + echo content >>mode_test && + test_tick && git commit -m "append to mode_test" mode_test && + test_file_mode_HEAD 100644 mode_test && + git tag mode_test_reverse_initial && + + git format-patch -1 --stdout >patch && + test_grep "^index .* 100644$" patch +' + +test_expect_success 'git apply warns about incorrect file modes' ' + test_config core.fileMode false && + git reset --hard mode_test_forward_initial && + + git add --chmod=+x mode_test && + test_file_mode_staged 100755 mode_test && + test_tick && git commit -m "make mode_test executable" && + test_file_mode_HEAD 100755 mode_test && + + git apply --index patch 2>err && + test_grep "has type 100755, expected 100644" err && + test_file_mode_staged 100755 mode_test && + test_tick && git commit -m "redo: append to mode_test" && + test_file_mode_HEAD 100755 mode_test +' + +test_expect_success 'git apply --reverse warns about incorrect file modes' ' + test_config core.fileMode false && + git reset --hard mode_test_reverse_initial && + + git add --chmod=+x mode_test && + test_file_mode_staged 100755 mode_test && + test_tick && git commit -m "make mode_test executable" && + test_file_mode_HEAD 100755 mode_test && + + git apply --index --reverse patch 2>err && + test_grep "has type 100755, expected 100644" err && + test_file_mode_staged 100755 mode_test && + test_tick && git commit -m "undo: append to mode_test" && + test_file_mode_HEAD 100755 mode_test ' test_expect_success POSIXPERM 'patch mode for new file is canonicalized' ' From 1d9a66493be9fef38e531da587dd47f6f17ea483 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Fri, 23 May 2025 23:40:46 -0400 Subject: [PATCH 07/21] apply: set file mode when --reverse creates a deleted file Commit 01aff0a (apply: correctly reverse patch's pre- and post-image mode bits, 2023-12-26) revised reverse_patches() to maintain the desired property that when only one of patch::old_mode and patch::new_mode is set, the mode will be carried in old_mode. That property is generally correct, with one notable exception: when creating a file, only new_mode will be set. Since reversing a deletion results in a creation, new_mode must be set in that case. Omitting handling for this case means that reversing a patch that removes an executable file will not result in the executable permission being set on the re-created file. Existing test coverage for file modes focuses only on mode changes of existing files. Swap old_mode and new_mode in reverse_patches() for what's represented in the patch as a file deletion, as it is transformed into a file creation under reversal. This causes git apply --reverse to set the executable permission properly when re-creating a deleted executable file. Add tests ensuring that git apply sets file modes correctly on file creation, both in the forward and reverse directions. Signed-off-by: Mark Mentovai Signed-off-by: Junio C Hamano --- apply.c | 2 +- t/t4129-apply-samemode.sh | 165 +++++++++++++++++++++++++++++++++++++- 2 files changed, 164 insertions(+), 3 deletions(-) diff --git a/apply.c b/apply.c index 381d2e3652f4e0..8bbe6ed224032e 100644 --- a/apply.c +++ b/apply.c @@ -2219,7 +2219,7 @@ static void reverse_patches(struct patch *p) struct fragment *frag = p->fragments; SWAP(p->new_name, p->old_name); - if (p->new_mode) + if (p->new_mode || p->is_delete) SWAP(p->new_mode, p->old_mode); SWAP(p->is_new, p->is_delete); SWAP(p->lines_added, p->lines_deleted); diff --git a/t/t4129-apply-samemode.sh b/t/t4129-apply-samemode.sh index bf4e7609dc335b..1d6317bd7141e0 100755 --- a/t/t4129-apply-samemode.sh +++ b/t/t4129-apply-samemode.sh @@ -102,14 +102,23 @@ test_expect_success POSIXPERM 'do not use core.sharedRepository for working tree ) ' +test_file_mode_common () { + if test "$1" = "000000" + then + test_must_be_empty "$2" + else + test_grep "^$1 " "$2" + fi +} + test_file_mode_staged () { git ls-files --stage -- "$2" >ls-files-output && - test_grep "^$1 " ls-files-output + test_file_mode_common "$1" ls-files-output } test_file_mode_HEAD () { git ls-tree HEAD -- "$2" >ls-tree-output && - test_grep "^$1 " ls-tree-output + test_file_mode_common "$1" ls-tree-output } test_expect_success 'git apply respects core.fileMode' ' @@ -189,6 +198,158 @@ test_expect_success 'git apply --reverse warns about incorrect file modes' ' test_file_mode_HEAD 100755 mode_test ' +test_expect_success 'setup: git apply [--reverse] restores file modes (change_x_to_notx)' ' + test_config core.fileMode false && + + touch change_x_to_notx && + git add --chmod=+x change_x_to_notx && + test_file_mode_staged 100755 change_x_to_notx && + test_tick && git commit -m "add change_x_to_notx as executable" && + test_file_mode_HEAD 100755 change_x_to_notx && + + git add --chmod=-x change_x_to_notx && + test_file_mode_staged 100644 change_x_to_notx && + test_tick && git commit -m "make change_x_to_notx not executable" && + test_file_mode_HEAD 100644 change_x_to_notx && + + git rm change_x_to_notx && + test_file_mode_staged 000000 change_x_to_notx && + test_tick && git commit -m "remove change_x_to_notx" && + test_file_mode_HEAD 000000 change_x_to_notx && + + git format-patch -o patches -3 && + mv patches/0001-* change_x_to_notx-0001-create-0755.patch && + mv patches/0002-* change_x_to_notx-0002-chmod-0644.patch && + mv patches/0003-* change_x_to_notx-0003-delete.patch && + + test_grep "^new file mode 100755$" change_x_to_notx-0001-create-0755.patch && + test_grep "^old mode 100755$" change_x_to_notx-0002-chmod-0644.patch && + test_grep "^new mode 100644$" change_x_to_notx-0002-chmod-0644.patch && + test_grep "^deleted file mode 100644$" change_x_to_notx-0003-delete.patch && + + git tag change_x_to_notx_initial +' + +test_expect_success 'git apply restores file modes (change_x_to_notx)' ' + test_config core.fileMode false && + git reset --hard change_x_to_notx_initial && + + git apply --index change_x_to_notx-0001-create-0755.patch && + test_file_mode_staged 100755 change_x_to_notx && + test_tick && git commit -m "redo: add change_x_to_notx as executable" && + test_file_mode_HEAD 100755 change_x_to_notx && + + git apply --index change_x_to_notx-0002-chmod-0644.patch 2>err && + test_grep ! "has type 100.*, expected 100.*" err && + test_file_mode_staged 100644 change_x_to_notx && + test_tick && git commit -m "redo: make change_x_to_notx not executable" && + test_file_mode_HEAD 100644 change_x_to_notx && + + git apply --index change_x_to_notx-0003-delete.patch 2>err && + test_grep ! "has type 100.*, expected 100.*" err && + test_file_mode_staged 000000 change_x_to_notx && + test_tick && git commit -m "redo: remove change_notx_to_x" && + test_file_mode_HEAD 000000 change_x_to_notx +' + +test_expect_success 'git apply --reverse restores file modes (change_x_to_notx)' ' + test_config core.fileMode false && + git reset --hard change_x_to_notx_initial && + + git apply --index --reverse change_x_to_notx-0003-delete.patch && + test_file_mode_staged 100644 change_x_to_notx && + test_tick && git commit -m "undo: remove change_x_to_notx" && + test_file_mode_HEAD 100644 change_x_to_notx && + + git apply --index --reverse change_x_to_notx-0002-chmod-0644.patch 2>err && + test_grep ! "has type 100.*, expected 100.*" err && + test_file_mode_staged 100755 change_x_to_notx && + test_tick && git commit -m "undo: make change_x_to_notx not executable" && + test_file_mode_HEAD 100755 change_x_to_notx && + + git apply --index --reverse change_x_to_notx-0001-create-0755.patch 2>err && + test_grep ! "has type 100.*, expected 100.*" err && + test_file_mode_staged 000000 change_x_to_notx && + test_tick && git commit -m "undo: add change_x_to_notx as executable" && + test_file_mode_HEAD 000000 change_x_to_notx +' + +test_expect_success 'setup: git apply [--reverse] restores file modes (change_notx_to_x)' ' + test_config core.fileMode false && + + touch change_notx_to_x && + git add --chmod=-x change_notx_to_x && + test_file_mode_staged 100644 change_notx_to_x && + test_tick && git commit -m "add change_notx_to_x as not executable" && + test_file_mode_HEAD 100644 change_notx_to_x && + + git add --chmod=+x change_notx_to_x && + test_file_mode_staged 100755 change_notx_to_x && + test_tick && git commit -m "make change_notx_to_x executable" && + test_file_mode_HEAD 100755 change_notx_to_x && + + git rm change_notx_to_x && + test_file_mode_staged 000000 change_notx_to_x && + test_tick && git commit -m "remove change_notx_to_x" && + test_file_mode_HEAD 000000 change_notx_to_x && + + git format-patch -o patches -3 && + mv patches/0001-* change_notx_to_x-0001-create-0644.patch && + mv patches/0002-* change_notx_to_x-0002-chmod-0755.patch && + mv patches/0003-* change_notx_to_x-0003-delete.patch && + + test_grep "^new file mode 100644$" change_notx_to_x-0001-create-0644.patch && + test_grep "^old mode 100644$" change_notx_to_x-0002-chmod-0755.patch && + test_grep "^new mode 100755$" change_notx_to_x-0002-chmod-0755.patch && + test_grep "^deleted file mode 100755$" change_notx_to_x-0003-delete.patch && + + git tag change_notx_to_x_initial +' + +test_expect_success 'git apply restores file modes (change_notx_to_x)' ' + test_config core.fileMode false && + git reset --hard change_notx_to_x_initial && + + git apply --index change_notx_to_x-0001-create-0644.patch && + test_file_mode_staged 100644 change_notx_to_x && + test_tick && git commit -m "redo: add change_notx_to_x as not executable" && + test_file_mode_HEAD 100644 change_notx_to_x && + + git apply --index change_notx_to_x-0002-chmod-0755.patch 2>err && + test_grep ! "has type 100.*, expected 100.*" err && + test_file_mode_staged 100755 change_notx_to_x && + test_tick && git commit -m "redo: make change_notx_to_x executable" && + test_file_mode_HEAD 100755 change_notx_to_x && + + git apply --index change_notx_to_x-0003-delete.patch && + test_grep ! "has type 100.*, expected 100.*" err && + test_file_mode_staged 000000 change_notx_to_x && + test_tick && git commit -m "undo: remove change_notx_to_x" && + test_file_mode_HEAD 000000 change_notx_to_x +' + +test_expect_success 'git apply --reverse restores file modes (change_notx_to_x)' ' + test_config core.fileMode false && + git reset --hard change_notx_to_x_initial && + + git apply --index --reverse change_notx_to_x-0003-delete.patch && + test_file_mode_staged 100755 change_notx_to_x && + test_tick && git commit -m "undo: remove change_notx_to_x" && + test_file_mode_HEAD 100755 change_notx_to_x && + + git apply --index --reverse change_notx_to_x-0002-chmod-0755.patch 2>err && + test_grep ! "has type 100.*, expected 100.*" err && + test_file_mode_staged 100644 change_notx_to_x && + test_tick && git commit -m "undo: make change_notx_to_x executable" && + test_file_mode_HEAD 100644 change_notx_to_x && + + git apply --index --reverse change_notx_to_x-0001-create-0644.patch 2>err && + test_grep ! "has type 100.*, expected 100.*" err && + test_file_mode_staged 000000 change_notx_to_x && + test_tick && git commit -m "undo: add change_notx_to_x as not executable" && + test_file_mode_HEAD 000000 change_notx_to_x +' + test_expect_success POSIXPERM 'patch mode for new file is canonicalized' ' cat >patch <<-\EOF && diff --git a/non-canon b/non-canon From 67cae845d21d3ca0dbdb51ecebb695b175fd1c8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Poho=C5=99elsk=C3=BD?= Date: Mon, 26 May 2025 13:48:25 +0000 Subject: [PATCH 08/21] cvsserver: remove unused escapeRefName function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Function 'escapeRefName' introduced in 51a7e6dbc9 has never been used. Despite being dead code, changes in Perl 5.41.4 exposed precedence warning within its logic, which then caused test failures in t9402 by logging the warnings to stderr while parsing the code. The affected tests are t9402.30, t9402.31, t9402.32 and t9402.34. Remove this unused function to simplify the codebase and stop the warnings and test failures. Its corresponding unescapeRefName function, which remains in use, has had its comments updated. Reported-by: Jitka Plesnikova Signed-off-by: Ondřej Pohořelský Signed-off-by: Junio C Hamano --- git-cvsserver.perl | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/git-cvsserver.perl b/git-cvsserver.perl index a4e1bad33ca2a3..d8d5422cbca90b 100755 --- a/git-cvsserver.perl +++ b/git-cvsserver.perl @@ -4986,13 +4986,13 @@ sub gethistorydense return $result; } -=head2 escapeRefName +=head2 unescapeRefName -Apply an escape mechanism to compensate for characters that +Undo an escape mechanism to compensate for characters that git ref names can have that CVS tags can not. =cut -sub escapeRefName +sub unescapeRefName { my($self,$refName)=@_; @@ -5009,27 +5009,6 @@ sub escapeRefName # = "_-xx-" Where "xx" is the hexadecimal representation of the # desired ASCII character byte. (for anything else) - if(! $refName=~/^[1-9][0-9]*(\.[1-9][0-9]*)*$/) - { - $refName=~s/_-/_-u--/g; - $refName=~s/\./_-p-/g; - $refName=~s%/%_-s-%g; - $refName=~s/[^-_a-zA-Z0-9]/sprintf("_-%02x-",$1)/eg; - } -} - -=head2 unescapeRefName - -Undo an escape mechanism to compensate for characters that -git ref names can have that CVS tags can not. - -=cut -sub unescapeRefName -{ - my($self,$refName)=@_; - - # see escapeRefName() for description of escape mechanism. - $refName=~s/_-([spu]|[0-9a-f][0-9a-f])-/unescapeRefNameChar($1)/eg; # allowed tag names From e2de9b354fd761d803a0d1d0cebf2d1c394ab338 Mon Sep 17 00:00:00 2001 From: Kristoffer Haugsbakk Date: Tue, 27 May 2025 23:19:30 +0200 Subject: [PATCH 09/21] doc: stripspace: mention where the default comes from Also quote `#` in line with the modern formatting convention. Signed-off-by: Kristoffer Haugsbakk Signed-off-by: Junio C Hamano --- Documentation/git-stripspace.adoc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Documentation/git-stripspace.adoc b/Documentation/git-stripspace.adoc index a293327581aa54..37287f211f062c 100644 --- a/Documentation/git-stripspace.adoc +++ b/Documentation/git-stripspace.adoc @@ -37,7 +37,8 @@ OPTIONS ------- -s:: --strip-comments:: - Skip and remove all lines starting with a comment character (default '#'). + Skip and remove all lines starting with a comment character + (`core.commentChar`, default `#`). -c:: --comment-lines:: From e2971d6f76cae5f8414f606be3c459e991093a15 Mon Sep 17 00:00:00 2001 From: Kristoffer Haugsbakk Date: Tue, 27 May 2025 23:19:31 +0200 Subject: [PATCH 10/21] doc: config: mention core.commentChar on commit.cleanup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mention it in parentheses since we are in a configuration context. Refer to the default as such, not as “the” character. Also don’t mention `#` again; just say “comment character”. Signed-off-by: Kristoffer Haugsbakk Signed-off-by: Junio C Hamano --- Documentation/config/commit.adoc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Documentation/config/commit.adoc b/Documentation/config/commit.adoc index d3f4624fd27811..208ae76c816f3b 100644 --- a/Documentation/config/commit.adoc +++ b/Documentation/config/commit.adoc @@ -8,10 +8,11 @@ endif::git-commit[] This setting overrides the default of the `--cleanup` option in `git commit`. {see-git-commit} Changing the default can be useful when you always want to keep lines that begin - with the comment character `#` in your log message, in which case you + with the comment character (`core.commentChar`, default `#`) + in your log message, in which case you would do `git config commit.cleanup whitespace` (note that you will - have to remove the help lines that begin with `#` in the commit log - template yourself, if you do this). + have to remove the help lines that begin with the comment character + in the commit log template yourself, if you do this). `commit.gpgSign`:: A boolean to specify whether all commits should be GPG signed. From 37dd51a6ebc58bdd1ed9eeed7015f2f09fc710b7 Mon Sep 17 00:00:00 2001 From: Kristoffer Haugsbakk Date: Tue, 27 May 2025 23:19:32 +0200 Subject: [PATCH 11/21] doc: notes: split out options with negated forms Split these out so that they are easier to search for.[1] [1]: https://lore.kernel.org/git/xmqqcyct1mtq.fsf@gitster.g/ Signed-off-by: Kristoffer Haugsbakk Signed-off-by: Junio C Hamano --- Documentation/git-notes.adoc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Documentation/git-notes.adoc b/Documentation/git-notes.adoc index bcfe3dacd3f0de..8706b33f2eeb56 100644 --- a/Documentation/git-notes.adoc +++ b/Documentation/git-notes.adoc @@ -174,14 +174,16 @@ OPTIONS Allow an empty note object to be stored. The default behavior is to automatically remove empty notes. -`--[no-]separator`:: `--separator=`:: +`--separator`:: +`--no-separator`:: Specify a string used as a custom inter-paragraph separator (a newline is added at the end as needed). If `--no-separator`, no separators will be added between paragraphs. Defaults to a blank line. -`--[no-]stripspace`:: +`--stripspace`:: +`--no-stripspace`:: Strip leading and trailing whitespace from the note message. Also strip out empty lines other than a single line between paragraphs. Lines starting with `#` will be stripped out From 6521ca8ec4b974de59e21640bf694bdb24cbda56 Mon Sep 17 00:00:00 2001 From: Kristoffer Haugsbakk Date: Tue, 27 May 2025 23:19:33 +0200 Subject: [PATCH 12/21] doc: notes: rework --[no-]stripspace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Document this option by copying the bullet list from git-stripspace(1). A bullet list is cleaner when there are this many points to consider. We also get a more standardized description of the multiple-blank-lines behavior. Compare the repeating (git-notes(1)): empty lines other than a single line between paragraphs With (git-stripspace(1)): multiple consecutive empty lines And: leading [...] whitespace With: empty lines from the beginning Leading whitespace in the form of spaces (indentation) are not removed. However, empty lines at the start of the message are removed. Note that we drop the mentions of comment line handling because they are wrong; this option does not control how lines which can be recognized as comment lines are handled. Only interactivity controls that: • Comment lines are stripped after editing interactively • Lines which could be recognized as comment lines are left alone when the message is given non-interactively So it is misleading to document the comment line behavior on this option. Further, the text is wrong: Lines starting with `#` will be stripped out in non-editor cases like `-m`, [...] Comment lines are still indirectly discussed on other options. We will deal with them in the next commit. Signed-off-by: Kristoffer Haugsbakk Signed-off-by: Junio C Hamano --- Documentation/git-notes.adoc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Documentation/git-notes.adoc b/Documentation/git-notes.adoc index 8706b33f2eeb56..d672794a9427a0 100644 --- a/Documentation/git-notes.adoc +++ b/Documentation/git-notes.adoc @@ -184,11 +184,13 @@ OPTIONS `--stripspace`:: `--no-stripspace`:: - Strip leading and trailing whitespace from the note message. - Also strip out empty lines other than a single line between - paragraphs. Lines starting with `#` will be stripped out - in non-editor cases like `-m`, `-F` and `-C`, but not in - editor case like `git notes edit`, `-c`, etc. + Clean up whitespace. Specifically (see + linkgit:git-stripspace[1]): ++ +- remove trailing whitespace from all lines +- collapse multiple consecutive empty lines into one empty line +- remove empty lines from the beginning and end of the input +- add a missing `\n` to the last line if necessary. `--ref `:: Manipulate the notes tree in __. This overrides From 159c42a063617230d57ac0030f37d722e9f07baa Mon Sep 17 00:00:00 2001 From: Kristoffer Haugsbakk Date: Tue, 27 May 2025 23:19:34 +0200 Subject: [PATCH 13/21] doc: notes: remove stripspace discussion from other options MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleaning up whitespace in metadata is typical porcelain behavior and this default does not need to be pointed out.[1] Only speak up when the default `--stripspace` is not used. Also remove all misleading mentions of comment lines in the process; see the previous commit. Also remove the period that trails the parenthetical here. † 1: See `-F` in git-commit(1) which has nothing to say about whitespace cleanup. The cleanup discussion is on `--cleanup`. Signed-off-by: Kristoffer Haugsbakk Signed-off-by: Junio C Hamano --- Documentation/git-notes.adoc | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/Documentation/git-notes.adoc b/Documentation/git-notes.adoc index d672794a9427a0..383e8bca685285 100644 --- a/Documentation/git-notes.adoc +++ b/Documentation/git-notes.adoc @@ -144,26 +144,18 @@ OPTIONS Use the given note message (instead of prompting). If multiple `-m` options are given, their values are concatenated as separate paragraphs. - Lines starting with `#` and empty lines other than a - single line between paragraphs will be stripped out. - If you wish to keep them verbatim, use `--no-stripspace`. `-F `:: `--file=`:: Take the note message from the given file. Use `-` to read the note message from the standard input. - Lines starting with `#` and empty lines other than a - single line between paragraphs will be stripped out. - If you wish to keep them verbatim, use `--no-stripspace`. `-C `:: `--reuse-message=`:: Take the given blob object (for example, another note) as the note message. (Use `git notes copy ` instead to - copy notes between objects.). By default, message will be - copied verbatim, but if you wish to strip out the lines - starting with `#` and empty lines other than a single line - between paragraphs, use with `--stripspace` option. + copy notes between objects.) Implies `--no-stripspace` since + the default behavior is to copy the message verbatim. `-c `:: `--reedit-message=`:: From 5471b190f80f2781c4414e347162656ab3b0c4ef Mon Sep 17 00:00:00 2001 From: Kristoffer Haugsbakk Date: Tue, 27 May 2025 23:19:35 +0200 Subject: [PATCH 14/21] doc: notes: clearly state that --stripspace is the default MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Clearly state when which of the regular and negated form of the option take effect.[1] Also mention the subtle behavior that occurs when you mix options like `-m` and `-C`, including a note that it might be fixed in the future. The topic was brought up on v8 of the `--separator` series.[2][3] [1]: https://lore.kernel.org/git/xmqqcyct1mtq.fsf@gitster.g/ [2]: https://lore.kernel.org/git/xmqq4jp326oj.fsf@gitster.g/ † 3: v11 was the version that landed Helped-by: Junio C Hamano Signed-off-by: Kristoffer Haugsbakk Signed-off-by: Junio C Hamano --- Documentation/git-notes.adoc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/git-notes.adoc b/Documentation/git-notes.adoc index 383e8bca685285..ef5a939516e116 100644 --- a/Documentation/git-notes.adoc +++ b/Documentation/git-notes.adoc @@ -179,10 +179,19 @@ OPTIONS Clean up whitespace. Specifically (see linkgit:git-stripspace[1]): + +-- - remove trailing whitespace from all lines - collapse multiple consecutive empty lines into one empty line - remove empty lines from the beginning and end of the input - add a missing `\n` to the last line if necessary. +-- ++ +`--stripspace` is the default except for +`-C`/`--reuse-message`. However, keep in mind that this depends on the +order of similar options. For example, for `-C -m`, +`--stripspace` will be used because the default for `-m` overrides the +previous `-C`. This is a known limitation that may be fixed in the +future. `--ref `:: Manipulate the notes tree in __. This overrides From 6dcec8930c13dabaaa8bebf9fd18e6ffdcb06cc5 Mon Sep 17 00:00:00 2001 From: Kristoffer Haugsbakk Date: Tue, 27 May 2025 23:19:36 +0200 Subject: [PATCH 15/21] doc: notes: point out copy --stdin use with argv Unlike `remove --stdin`, this option cannot be combined with object names given via the command line. Signed-off-by: Kristoffer Haugsbakk Signed-off-by: Junio C Hamano --- Documentation/git-notes.adoc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Documentation/git-notes.adoc b/Documentation/git-notes.adoc index ef5a939516e116..9ce71ec34552c5 100644 --- a/Documentation/git-notes.adoc +++ b/Documentation/git-notes.adoc @@ -87,6 +87,9 @@ In `--stdin` mode, take lines in the format on standard input, and copy the notes from each __ to its corresponding __. (The optional __ is ignored so that the command can read the input given to the `post-rewrite` hook.) ++ +`--stdin` cannot be combined with object names given on the command +line. `append`:: Append new message(s) given by `-m` or `-F` options to an From 45113e142e188bed5a747fd8a45629bc83c9e3eb Mon Sep 17 00:00:00 2001 From: Kristoffer Haugsbakk Date: Tue, 27 May 2025 23:19:37 +0200 Subject: [PATCH 16/21] doc: notes: treat --stdin equally between copy/remove MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 46538012d94 (notes remove: --stdin reads from the standard input, 2011-05-18) added `--stdin` for the `remove` subcommand, documenting it in the “Options” section. But `copy --stdin` was added before that, in 160baa0d9cb (notes: implement 'git notes copy --stdin', 2010-03-12). Treat this option equally between the two subcommands: • remove: mention `--stdin` on the subcommand as well, like for `copy` • copy: mention it as well under the option documentation Signed-off-by: Kristoffer Haugsbakk Signed-off-by: Junio C Hamano --- Documentation/git-notes.adoc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Documentation/git-notes.adoc b/Documentation/git-notes.adoc index 9ce71ec34552c5..397f6caa92a35d 100644 --- a/Documentation/git-notes.adoc +++ b/Documentation/git-notes.adoc @@ -127,6 +127,10 @@ When done, the user can either finalize the merge with giving zero or one object from the command line, this is equivalent to specifying an empty note message to the `edit` subcommand. ++ +In `--stdin` mode, also remove the object names given on standard +input. In other words, `--stdin` can be combined with object names from +the command line. `prune`:: Remove all notes for non-existing/unreachable objects. @@ -208,9 +212,7 @@ future. object that does not have notes attached to it. `--stdin`:: - Also read the object names to remove notes from the standard - input (there is no reason you cannot combine this with object - names from the command line). + Only valid for `remove` and `copy`. See the respective subcommands. `-n`:: `--dry-run`:: From 806337c7052ccf3b11d2efd4ba031c21b241e64a Mon Sep 17 00:00:00 2001 From: Kristoffer Haugsbakk Date: Tue, 27 May 2025 23:19:38 +0200 Subject: [PATCH 17/21] doc: notes: use stuck form throughout gitcli(7) recommends the *stuck form*. `--ref` is the only one which does not use it. Signed-off-by: Kristoffer Haugsbakk Signed-off-by: Junio C Hamano --- Documentation/git-notes.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/git-notes.adoc b/Documentation/git-notes.adoc index 397f6caa92a35d..46a232ca7185ad 100644 --- a/Documentation/git-notes.adoc +++ b/Documentation/git-notes.adoc @@ -200,7 +200,7 @@ order of similar options. For example, for `-C -m`, previous `-C`. This is a known limitation that may be fixed in the future. -`--ref `:: +`--ref=`:: Manipulate the notes tree in __. This overrides `GIT_NOTES_REF` and the `core.notesRef` configuration. The ref specifies the full refname when it begins with `refs/notes/`; when it From 320572c43d7bc5afbcb8e5faf83b6eccfe6f4e32 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Wed, 28 May 2025 14:24:10 +0200 Subject: [PATCH 18/21] packfile: explain ordering of how we look up auxiliary pack files When adding a packfile to an object database we perform four syscalls: - Three calls to access(3p) are done to check for auxiliary data structures. - One call to stat(3p) is done to check for the ".pack" itself. One curious bit is that we perform the access(3p) calls before checking for the packfile itself, but if the packfile doesn't exist we discard all results. The access(3p) calls are thus essentially wasted, so one may be triggered to reorder those calls so that we can short-circuit the other syscalls in case the packfile does not exist. The order in which we look up files is quite important though to help avoid races: - When installing a packfile we move auxiliary data structures into place before we install the ".idx" file. - When deleting a packfile we first delete the ".idx" and ".pack" files before deleting auxiliary data structures. As such, to avoid any races with concurrently created or deleted packs we need to make sure that we _first_ read auxiliary data structures before we read the corresponding ".idx" or ".pack" file. Otherwise it may easily happen that we return a populated but misclassified pack. Add a comment to `add_packed_git()` to make future readers aware of this ordering requirement. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- packfile.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packfile.c b/packfile.c index d91016f1c7ff40..933036e26062f1 100644 --- a/packfile.c +++ b/packfile.c @@ -737,6 +737,17 @@ struct packed_git *add_packed_git(struct repository *r, const char *path, p = alloc_packed_git(r, alloc); memcpy(p->pack_name, path, path_len); + /* + * Note that we have to check auxiliary data structures before we check + * for the ".pack" file to exist to avoid races with a packfile that is + * in the process of being deleted. The ".pack" file is unlinked before + * its auxiliary data structures, so we know that we either get a + * consistent snapshot of all data structures or that we'll fail to + * stat(3p) the packfile itself and thus return `NULL`. + * + * As such, we cannot bail out before the access(3p) calls in case the + * packfile doesn't exist without doing two stat(3p) calls for it. + */ xsnprintf(p->pack_name + path_len, alloc - path_len, ".keep"); if (!access(p->pack_name, F_OK)) p->pack_keep = 1; From 1f34bf3e082741e053d25b76a0ffe31d9d967594 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Wed, 28 May 2025 14:24:11 +0200 Subject: [PATCH 19/21] midx: stop repeatedly looking up nonexistent packfiles MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The multi-pack index acts as a cache across a set of packfiles so that we can quickly look up which of those packfiles contains a given object. As such, the multi-pack index naturally needs to be updated every time one of the packfiles goes away, or otherwise the multi-pack index has grown stale. A stale multi-pack index should be handled gracefully by Git though, and in fact it is: if the indexed pack cannot be found we simply ignore it and eventually we fall back to doing the object lookup by just iterating through all packs, even if those aren't indexed. But while this fallback works, it has one significant downside: we don't cache the fact that a pack has vanished. This leads to us repeatedly trying to look up the same pack only to realize that it (still) doesn't exist. This issue can be easily demonstrated by creating a repository with a stale multi-pack index and a couple of objects. We do so by creating a repository with two packfiles, both of which are indexed by the multi-pack index, and then repack those two packfiles. Note that we have to move the multi-pack-index before doing the final repack, as Git knows to delete it otherwise. $ git init repo $ cd repo/ $ git config set maintenance.auto false $ for i in $(seq 1000); do printf "%d-original" $i >file-$i; done $ git add . $ git commit -moriginal $ git repack -dl $ for i in $(seq 1000); do printf "%d-modified" $i >file-$i; done $ git commit -a -mmodified $ git repack -dl $ git multi-pack-index write $ mv .git/objects/pack/multi-pack-index . $ git repack -Adl $ mv multi-pack-index .git/objects/pack/ Commands that cause a lot of objects lookups will now repeatedly invoke `add_packed_git()`, which leads to three failed access(3p) calls as well as one failed stat(3p) call. The following strace for example is done for `git log --patch` in the above repository: % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 74.67 0.024693 1 18038 18031 access 25.33 0.008378 1 6045 6017 newfstatat ------ ----------- ----------- --------- --------- ---------------- 100.00 0.033071 1 24083 24048 total Fix the issue by introducing a negative lookup cache for indexed packs. This cache works by simply storing an invalid pointer for a missing pack when `prepare_midx_pack()` fails to look up the pack. Most users of the `packs` array don't need to be adjusted, either, as they all know to call `prepare_midx_pack()` before accessing the array. With this change in place we can now see a significantly reduced number of syscalls: % time seconds usecs/call calls errors syscall ------ ----------- ----------- --------- --------- ---------------- 73.58 0.000323 5 60 28 newfstatat 26.42 0.000116 5 23 16 access ------ ----------- ----------- --------- --------- ---------------- 100.00 0.000439 5 83 44 total Furthermore, this change also results in a speedup: Benchmark 1: git log --patch (revision = HEAD~) Time (mean ± σ): 50.4 ms ± 2.5 ms [User: 22.0 ms, System: 24.4 ms] Range (min … max): 45.4 ms … 54.9 ms 53 runs Benchmark 2: git log --patch (revision = HEAD) Time (mean ± σ): 12.7 ms ± 0.4 ms [User: 11.1 ms, System: 1.6 ms] Range (min … max): 12.4 ms … 15.0 ms 191 runs Summary git log --patch (revision = HEAD) ran 3.96 ± 0.22 times faster than git log --patch (revision = HEAD~) In the end, it should in theory never be necessary to have this negative lookup cache given that we know to update the multi-pack index together with repacks. But as the change is quite contained and as the speedup can be significant as demonstrated above, it does feel sensible to have the negative lookup cache regardless. Based-on-patch-by: Jeff King Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- midx.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/midx.c b/midx.c index 3d0015f782818c..cd6e766ce2b158 100644 --- a/midx.c +++ b/midx.c @@ -13,6 +13,8 @@ #include "pack-bitmap.h" #include "pack-revindex.h" +#define MIDX_PACK_ERROR ((void *)(intptr_t)-1) + int midx_checksum_valid(struct multi_pack_index *m); void clear_midx_files_ext(const char *object_dir, const char *ext, const char *keep_hash); @@ -405,7 +407,7 @@ void close_midx(struct multi_pack_index *m) munmap((unsigned char *)m->data, m->data_len); for (i = 0; i < m->num_packs; i++) { - if (m->packs[i]) + if (m->packs[i] && m->packs[i] != MIDX_PACK_ERROR) m->packs[i]->multi_pack_index = 0; } FREE_AND_NULL(m->packs); @@ -458,6 +460,8 @@ int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, pack_int_id = midx_for_pack(&m, pack_int_id); + if (m->packs[pack_int_id] == MIDX_PACK_ERROR) + return 1; if (m->packs[pack_int_id]) return 0; @@ -482,8 +486,10 @@ int prepare_midx_pack(struct repository *r, struct multi_pack_index *m, strbuf_release(&pack_name); strbuf_release(&key); - if (!p) + if (!p) { + m->packs[pack_int_id] = MIDX_PACK_ERROR; return 1; + } p->multi_pack_index = 1; m->packs[pack_int_id] = p; @@ -495,6 +501,8 @@ struct packed_git *nth_midxed_pack(struct multi_pack_index *m, uint32_t pack_int_id) { uint32_t local_pack_int_id = midx_for_pack(&m, pack_int_id); + if (m->packs[local_pack_int_id] == MIDX_PACK_ERROR) + return NULL; return m->packs[local_pack_int_id]; } From f1228cd12c129a7e4da317e1d21741a3ec26e07e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlo=20Marcelo=20Arenas=20Bel=C3=B3n?= Date: Thu, 29 May 2025 03:11:36 -0700 Subject: [PATCH 20/21] reftable: make REFTABLE_UNUSED C99 compatible MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since f93b2a0424 (reftable/basics: introduce `REFTABLE_UNUSED` annotation, 2025-02-18), the reftable library was migrated to use an internal version of `UNUSED`, which unconditionally sets a GNU __attribute__ to avoid warnings function parameters that are not being used. Make the definition conditional to prevent breaking the build with non GNU compilers. Reported-by: "Randall S. Becker" Signed-off-by: Carlo Marcelo Arenas Belón Signed-off-by: Junio C Hamano --- reftable/basics.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/reftable/basics.h b/reftable/basics.h index d8888c126290cf..7d22f96261072a 100644 --- a/reftable/basics.h +++ b/reftable/basics.h @@ -16,7 +16,11 @@ #include "system.h" #include "reftable-basics.h" +#ifdef __GNUC__ #define REFTABLE_UNUSED __attribute__((__unused__)) +#else +#define REFTABLE_UNUSED +#endif /* * Initialize the buffer such that it is ready for use. This is equivalent to From 7014b55638da979331baf8dc31c4e1d697cf2d67 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 30 May 2025 11:59:01 -0700 Subject: [PATCH 21/21] A bit more topics for -rc1 Signed-off-by: Junio C Hamano --- Documentation/RelNotes/2.50.0.adoc | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Documentation/RelNotes/2.50.0.adoc b/Documentation/RelNotes/2.50.0.adoc index c6c34d1a1d60eb..b3bfdf29c955f7 100644 --- a/Documentation/RelNotes/2.50.0.adoc +++ b/Documentation/RelNotes/2.50.0.adoc @@ -89,6 +89,8 @@ UI, Workflows & Features check, which can be useful when the repository arranges to ensure connectivity by some other means. + * "git notes --help" documentation updates. + Performance, Internal Implementation, Development Support etc. -------------------------------------------------------------- @@ -193,6 +195,10 @@ Performance, Internal Implementation, Development Support etc. do not pass the leak checker tests, as they should no longer be needed. + * When a stale .midx file refers to .pack files that no longer exist, + we ended up checking for these non-existent files repeatedly, which + has been optimized by memoizing the non-existence. + Fixes since v2.49 ----------------- @@ -355,6 +361,22 @@ Fixes since v2.49 expand sparse-index while working. (merge ecf9ba20e3 ds/sparse-apply-add-p later to maint). + * Avoid adding directory path to a sparse-index tree entries to the + name-hash, since they would bloat the hashtable without anybody + querying for them. This was done already for a single threaded + part of the code, but now the multi-threaded code also does the + same. + (merge 2e60aabc75 am/sparse-index-name-hash-fix later to maint). + + * Recent versions of Perl started warning against "! A =~ /pattern/" + which does not negate the result of the matching. As it turns out + that the problematic function is not even called, it was removed. + (merge 67cae845d2 op/cvsserver-perl-warning later to maint). + + * "git apply --index/--cached" when applying a deletion patch in + reverse failed to give the mode bits of the path "removed" by the + patch to the file it creates, which has been corrected. + * Other code cleanup, docfix, build fix, etc. (merge 227c4f33a0 ja/doc-block-delimiter-markup-fix later to maint). (merge 2bfd3b3685 ab/decorate-code-cleanup later to maint).