* Re: [PATCH] meson: restore hook-list.h to builtin_sources
From: Patrick Steinhardt @ 2026-07-02 11:06 UTC (permalink / raw)
To: Mike Gilbert; +Cc: git, adrian.ratiu
In-Reply-To: <20260701193928.358825-1-floppym@gentoo.org>
On Wed, Jul 01, 2026 at 03:39:28PM -0400, Mike Gilbert wrote:
> This fixes a racy build failure.
>
> ```
> builtin/bugreport.c:12:10: fatal error: hook-list.h: No such file or directory
> 12 | #include "hook-list.h"
> | ^~~~~~~~~~~~~
>
> ```
>
> hook-list.h must be generated before builtin/bugreport.c is compiled.
"hook-list.h" is required by both "hook.c" and by "builtin/bugreport.c".
So you would expect that we indeed need the header generated for both of
these, but right now we only explicitly list the dependency for our
libgit sources, not to our builtin sources. And consequently the header
may not be generated:
$ meson setup build
...
$ ninja -C build git.p/builtin_bugreport.c.o
...
../builtin/bugreport.c:12:10: fatal error: 'hook-list.h' file not found
12 | #include "hook-list.h"
| ^~~~~~~~~~~~~
1 error generated.
The fix is of course to explicitly list the header for both targets.
And...
> diff --git a/meson.build b/meson.build
> index 3247697f74aa..bdc83843e8e0 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -278,7 +278,20 @@ compat_sources = [
> 'compat/terminal.c',
> ]
>
> +hook_list = custom_target(
> + input: 'Documentation/githooks.adoc',
> + output: 'hook-list.h',
> + command: [
> + shell,
> + meson.current_source_dir() + '/tools/generate-hooklist.sh',
> + meson.current_source_dir(),
> + '@OUTPUT@',
> + ],
> + env: script_environment,
> +)
> +
> libgit_sources = [
> + hook_list,
> 'abspath.c',
> 'add-interactive.c',
> 'add-patch.c',
> @@ -566,19 +579,8 @@ libgit_sources += custom_target(
> env: script_environment,
> )
>
> -libgit_sources += custom_target(
> - input: 'Documentation/githooks.adoc',
> - output: 'hook-list.h',
> - command: [
> - shell,
> - meson.current_source_dir() + '/tools/generate-hooklist.sh',
> - meson.current_source_dir(),
> - '@OUTPUT@',
> - ],
> - env: script_environment,
> -)
> -
> builtin_sources = [
> + hook_list,
> 'builtin/add.c',
> 'builtin/am.c',
> 'builtin/annotate.c',
... that's exactly what you do. So this fix looks good to me, thanks!
Patrick
^ permalink raw reply
* Re: [PATCH v2] Makefile: link osxkeychain & support universal Rust
From: Patrick Steinhardt @ 2026-07-02 11:50 UTC (permalink / raw)
To: Shardul Natu via GitGitGadget
Cc: git, Kristoffer Haugsbakk, Shnatu, Koji Nakamaru
In-Reply-To: <pull.2288.v2.git.git.1782943303219.gitgitgadget@gmail.com>
On Wed, Jul 01, 2026 at 10:01:43PM +0000, Shardul Natu via GitGitGadget wrote:
> From: Shnatu <snatu@google.com>
>
> When Rust is enabled, ensure that the git-credential-osxkeychain
> helper is linked with the necessary Rust libraries.
>
> Also, introduce native support for macOS Universal Binaries
> (multi-architecture builds) in the Git build system by allowing
> the user to specify a list of target triples in the RUST_TARGETS
> environment variable.
These are fundamentally unrelated things, aren't they? So I'd argue they
should be split up into two commits.
I think we could also use an explanation here what the universal binary
buys us for those who are not deeply familiar with the macOS platform.
What are they, and why do we want/need to support them?
> To implement this cleanly without complex shell scripting in recipes:
> 1. We introduce a declarative Make pattern rule (target/%/...) to
> compile each target-specific library slice (e.g.,
> target/aarch64-apple-darwin/...).
> 2. We update the $(RUST_LIB) recipe to depend on the list of
> compiled target-specific member libraries ($(RUST_MEMBER_LIBS)).
> 3. On macOS, if multiple targets are specified, we use lipo to
> combine them into a single Universal static library at
> target/release/libgitcore.a.
> 4. If only one target is specified, we copy it to the standard
> path.
> 5. We enforce that building for multiple targets requires macOS
> (as lipo is only available there), raising a clear make error
> on other platforms.
>
> This is a highly elegant and native Makefile solution that avoids
> complex shell scripting in recipes and fully supports macOS Universal
> Binaries.
As Junio already pointed out this self-praise reads quite weird. I'm
just going to assume that this is AI-generated fluff.
> diff --git a/Makefile b/Makefile
> index 1f3f099f5c..8d49ecc897 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -3019,11 +3030,33 @@ scalar$X: scalar.o GIT-LDFLAGS $(GITLIBS)
> $(LIB_FILE): $(LIB_OBJS)
> $(QUIET_AR)$(RM) $@ && $(AR) $(ARFLAGS) $@ $^
>
> +ifndef NO_RUST
> +ifeq ($(RUST_TARGETS),)
> $(RUST_LIB): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
> $(QUIET_CARGO)cargo build $(CARGO_ARGS)
> +else
> +ifneq ($(words $(RUST_TARGETS)),1)
> +ifneq ($(uname_S),Darwin)
> +$(error Building universal Rust libraries requires macOS (lipo is not available on $(uname_S)))
> +endif
> +endif
> +
> +RUST_MEMBER_LIBS = $(foreach target,$(RUST_TARGETS),target/$(target)/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME))
> +$(RUST_MEMBER_LIBS): target/%/$(RUST_BUILD_CONFIG)/$(RUST_LIB_NAME): Cargo.toml $(RUST_SOURCES) $(LIB_FILE)
>
> + $(QUIET_CARGO)cargo build $(CARGO_ARGS) --target $*
> +
> +$(RUST_LIB): $(RUST_MEMBER_LIBS)
> + $(QUIET_GEN)\
> + if [ $(words $(RUST_TARGETS)) -gt 1 ]; then \
> + lipo -create $^ -output $@; \
Can we assume lipo to be generally available on macOS? Also, is it
sufficient to just do this for the library? I would have expected that
binaries would also need some treatment there.
In other words: what does it help us to have the Rust treated this way
if the rest isn't?
Thanks!
Patrick
^ permalink raw reply
* [PATCH 0/9] t: fixes and improvements for GIT_TEST_LONG
From: Patrick Steinhardt @ 2026-07-02 12:00 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Johannes Schindelin
Hi,
this series started out as a simple two-patch series that wired up the
GitLab CI badge in our README and GIT_TEST_LONG for GitLab CI. But as it
typically goes, tests broke on GitLab CI, which made me realize that
they are broken even on GitHub's master branch right now. Some tests are
failing in the linux32 job, and we only didn't notice because the whole
pipeline hangs.
So I had to go down the rabbit hole a bit, the result of which is this
patch series.
Thanks!
Patrick
[1]: <akIfsaVMB_S6kfJQ@pks.im>
---
Patrick Steinhardt (9):
README: add GitLab CI badge to make it more discoverable
t0021: skip EXPENSIVE test that is broken without SIZE_T_IS_32BIT
t4141: fix inefficient use of dd(1)
t5608: reduce maximum disk usage
t7508: skip EXPENSIVE test that is broken without SIZE_T_IS_32BIT
t7900: clean up large EXPENSIVE repository
t: use `test_bool_env` to parse GIT_TEST_LONG
gitlab-ci: disable RAM disk on macOS jobs
gitlab-ci: enable "GIT_TEST_LONG"
.gitlab-ci.yml | 13 ++++-----
README.md | 3 ++-
ci/lib.sh | 12 +++++++--
t/t0021-conversion.sh | 2 +-
t/t4141-apply-too-large.sh | 7 +++--
t/t5608-clone-2gb.sh | 66 ++++++++++++++++++++++++----------------------
t/t7508-status.sh | 2 +-
t/t7900-maintenance.sh | 56 +++++++++++++++++++++------------------
t/test-lib.sh | 4 +--
9 files changed, 92 insertions(+), 73 deletions(-)
---
base-commit: e9019fcafe0040228b8631c30f97ae1adb61bcdc
change-id: 20260701-b4-pks-t-fixes-for-GIT-TEST-LONG-78e538bf0e06
^ permalink raw reply
* [PATCH 1/9] README: add GitLab CI badge to make it more discoverable
From: Patrick Steinhardt @ 2026-07-02 12:00 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Johannes Schindelin
In-Reply-To: <20260702-b4-pks-t-fixes-for-GIT-TEST-LONG-v1-0-76b4d7bab3d0@pks.im>
The Git project uses CI systems from both GitHub and GitLab. While both
of these systems are extensively used in day-to-day work, we only have a
link to the GitHub Workflows in our README, which makes the GitLab CI
hard to discover.
Improve the situation by adding a second badge for GitLab CI to our
README.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/README.md b/README.md
index d87bca1b8c..46489b0971 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,5 @@
-[](https://github.com/git/git/actions?query=branch%3Amaster+event%3Apush)
+[](https://github.com/git/git/actions?query=branch%3Amaster+event%3Apush)
+[](https://gitlab.com/git-scm/git/-/pipelines?ref=master)
Git - fast, scalable, distributed revision control system
=========================================================
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH 2/9] t0021: skip EXPENSIVE test that is broken without SIZE_T_IS_32BIT
From: Patrick Steinhardt @ 2026-07-02 12:00 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Johannes Schindelin
In-Reply-To: <20260702-b4-pks-t-fixes-for-GIT-TEST-LONG-v1-0-76b4d7bab3d0@pks.im>
One of the tests in t0021 writes a 2GB file and then roundtrips it
through the clean/sumdge filters. This test is broken on 32 bit
platforms because they typically don't handle files larger then
`SSIZE_MAX` well at all.
While our CI has a "linux32" job that should in theory hit this issue,
we never noticed it because we didn't use to run EXPENSIVE tests until
7a094d68a2 (ci: run expensive tests on push builds to integration
branches, 2026-05-08). And after that commit, the test does not fail but
instead hangs completely.
Ideally, we'd of course properly detect this situation and then test for
it. In practice, this turns out to be hard as the test failure are not
reliable as they often (but not always) run into ENOMEM errors.
Instead, skip the test altogether.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
t/t0021-conversion.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/t/t0021-conversion.sh b/t/t0021-conversion.sh
index 033b00a364..7b9a0ca877 100755
--- a/t/t0021-conversion.sh
+++ b/t/t0021-conversion.sh
@@ -296,7 +296,7 @@ test_expect_success 'filter that does not read is fine' '
test_cmp expect actual
'
-test_expect_success EXPENSIVE 'filter large file' '
+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'filter large file' '
test_config filter.largefile.smudge cat &&
test_config filter.largefile.clean cat &&
test_seq -f "%1048576d" 1 2048 >2GB &&
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH 3/9] t4141: fix inefficient use of dd(1)
From: Patrick Steinhardt @ 2026-07-02 12:00 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Johannes Schindelin
In-Reply-To: <20260702-b4-pks-t-fixes-for-GIT-TEST-LONG-v1-0-76b4d7bab3d0@pks.im>
In t4141 we generate a patch that is roughly 1GB in size to verify that
git-apply(1) indeed rejects that patch. We generate that patch by
prepending a patch header and then executing `test-tool genzeros`
without a limit. This causes us to print infinitely many zeros, and we
limit the overall amount of generated bytes via `test_copy_bytes`.
This test setup is extremely expensive, as `test_copy_bytes` is
implemented via `dd ibs=1 count="$1"`, which copies data one byte at a
time. So as we write 1GB of data, we end up doing 1 billion reads and
writes. This naturally takes a while: it takes 6 minutes on my system,
and around 40 minutes in some CI jobs!
We can do much better though, as genzeros already knows to handle an
optional limit of how much data it is supposed to write, which allows us
to remove the call to `test_copy_bytes`. Furthermore, it has already
been optimized to generate the data fast.
And indeed, doing this conversion drops the test execution to less than
a second on my machine, so that we can drop the EXPENSIVE prerequisite.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
t/t4141-apply-too-large.sh | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/t/t4141-apply-too-large.sh b/t/t4141-apply-too-large.sh
index eac6f7e151..dad67779ed 100755
--- a/t/t4141-apply-too-large.sh
+++ b/t/t4141-apply-too-large.sh
@@ -4,8 +4,7 @@ test_description='git apply with too-large patch'
. ./test-lib.sh
-test_expect_success EXPENSIVE 'git apply rejects patches that are too large' '
- sz=$((1024 * 1024 * 1023)) &&
+test_expect_success 'git apply rejects patches that are too large' '
{
cat <<-\EOF &&
diff --git a/file b/file
@@ -14,8 +13,8 @@ test_expect_success EXPENSIVE 'git apply rejects patches that are too large' '
+++ b/file
@@ -0,0 +1 @@
EOF
- test-tool genzeros
- } | test_copy_bytes $sz | test_must_fail git apply 2>err &&
+ test-tool genzeros $((1024 * 1024 * 1023))
+ } | test_must_fail git apply 2>err &&
grep "patch too large" err
'
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH 4/9] t5608: reduce maximum disk usage
From: Patrick Steinhardt @ 2026-07-02 12:00 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Johannes Schindelin
In-Reply-To: <20260702-b4-pks-t-fixes-for-GIT-TEST-LONG-v1-0-76b4d7bab3d0@pks.im>
The tests in t5608 perform a couple of clones of repositories that are
somewhat large. Ultimately, we end up creating:
- A setup repository that contains 2GB of uncompressed pack data.
- A bare clone that contains the same 2GB of data.
- A clone with worktree writes a 2GB packfile and a 2GB worktree.
- A second setup repository that contains a 4GB packfile.
- Two 4GB clone of that repository.
Some of these clones ultimately hardlink files, which ensures that we at
least don't end up with more than 20GB of data. But at the end of the
test we still have around 16GB of data, which is only a tiny bit better.
Refactor the test to prune repositories after they have no use anymore.
This reduced the peak disk usage of this test to 8GB.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
t/t5608-clone-2gb.sh | 66 ++++++++++++++++++++++++++++------------------------
1 file changed, 35 insertions(+), 31 deletions(-)
diff --git a/t/t5608-clone-2gb.sh b/t/t5608-clone-2gb.sh
index 4f8a95ddda..5d56debf1c 100755
--- a/t/t5608-clone-2gb.sh
+++ b/t/t5608-clone-2gb.sh
@@ -10,45 +10,47 @@ then
fi
test_expect_success 'setup' '
-
- git config pack.compression 0 &&
- git config pack.depth 0 &&
- blobsize=$((100*1024*1024)) &&
- blobcount=$((2*1024*1024*1024/$blobsize+1)) &&
- i=1 &&
- (while test $i -le $blobcount
- do
- printf "Generating blob $i/$blobcount\r" >&2 &&
- printf "blob\nmark :$i\ndata $blobsize\n" &&
- #test-tool genrandom $i $blobsize &&
- printf "%-${blobsize}s" $i &&
- echo "M 100644 :$i $i" >> commit &&
- i=$(($i+1)) ||
- echo $? > exit-status
- done &&
- echo "commit refs/heads/main" &&
- echo "author A U Thor <author@email.com> 123456789 +0000" &&
- echo "committer C O Mitter <committer@email.com> 123456789 +0000" &&
- echo "data 5" &&
- echo ">2gb" &&
- cat commit) |
- git fast-import --big-file-threshold=2 &&
- test ! -f exit-status
-
+ git init 2gb-repo &&
+ (
+ cd 2gb-repo &&
+ git config pack.compression 0 &&
+ git config pack.depth 0 &&
+ blobsize=$((100*1024*1024)) &&
+ blobcount=$((2*1024*1024*1024/$blobsize+1)) &&
+ i=1 &&
+ (while test $i -le $blobcount
+ do
+ printf "Generating blob $i/$blobcount\r" >&2 &&
+ printf "blob\nmark :$i\ndata $blobsize\n" &&
+ #test-tool genrandom $i $blobsize &&
+ printf "%-${blobsize}s" $i &&
+ echo "M 100644 :$i $i" >> commit &&
+ i=$(($i+1)) ||
+ echo $? > exit-status
+ done &&
+ echo "commit refs/heads/main" &&
+ echo "author A U Thor <author@email.com> 123456789 +0000" &&
+ echo "committer C O Mitter <committer@email.com> 123456789 +0000" &&
+ echo "data 5" &&
+ echo ">2gb" &&
+ cat commit) |
+ git fast-import --big-file-threshold=2 &&
+ test ! -f exit-status
+ )
'
test_expect_success 'clone - bare' '
-
- git clone --bare --no-hardlinks . clone-bare
-
+ test_when_finished rm -rf clone-bare &&
+ git clone --bare --no-hardlinks 2gb-repo clone-bare
'
test_expect_success 'clone - with worktree, file:// protocol' '
-
- git clone "file://$(pwd)" clone-wt
-
+ test_when_finished rm -rf clone-wt &&
+ git clone "file://$(pwd)/2gb-repo" clone-wt
'
+rm -rf 2gb-repo 2>/dev/null
+
test_expect_success SIZE_T_IS_64BIT,EXPENSIVE 'set up repo with >4GB object' '
large_blob_size=$((4*1024*1024*1024+1)) &&
git init --bare 4gb-repo &&
@@ -61,6 +63,7 @@ test_expect_success SIZE_T_IS_64BIT,EXPENSIVE 'set up repo with >4GB object' '
'
test_expect_success SIZE_T_IS_64BIT,EXPENSIVE 'clone >4GB object via unpack-objects' '
+ test_when_finished rm -rf 4gb-clone-unpack &&
# The synthesized pack has five objects, so a large unpack limit keeps
# fetch-pack on the unpack-objects path.
git -c fetch.unpackLimit=100 clone --bare \
@@ -77,6 +80,7 @@ test_expect_success SIZE_T_IS_64BIT,EXPENSIVE 'clone >4GB object via unpack-obje
'
test_expect_success SIZE_T_IS_64BIT,EXPENSIVE 'clone with >4GB object via index-pack' '
+ test_when_finished rm -rf 4gb-clone-index &&
# Force fetch-pack to hand the pack to index-pack instead.
git -c fetch.unpackLimit=1 clone --bare \
"file://$(pwd)/4gb-repo" 4gb-clone-index &&
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH 5/9] t7508: skip EXPENSIVE test that is broken without SIZE_T_IS_32BIT
From: Patrick Steinhardt @ 2026-07-02 12:00 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Johannes Schindelin
In-Reply-To: <20260702-b4-pks-t-fixes-for-GIT-TEST-LONG-v1-0-76b4d7bab3d0@pks.im>
One of the tests in t7508 is marked as EXPENSIVE because it ends up
creating and adding files that are multiple gigabytes in size. This
takes a while to complete, hence the EXPENSIVE prerequisite.
Besides being expensive though the test can only work on systems where
`size_t` is at least 64 bit. This is because one of the created files
is larger than 4GB, and because Git tracks object size via `size_t` it
will eventually blow up.
This test has also been blowing up in the "linux32" CI job in GitHub
Workflows since 7a094d68a2 (ci: run expensive tests on push builds to
integration branches, 2026-05-08). But that job doesn't only fail, it
also hangs, and that has been concealing the failure.
Fix the issue by marking the test as requiring 64 bit `size_t`.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
t/t7508-status.sh | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/t/t7508-status.sh b/t/t7508-status.sh
index c2057bc94c..dfdd78b6fe 100755
--- a/t/t7508-status.sh
+++ b/t/t7508-status.sh
@@ -1773,7 +1773,7 @@ test_expect_success 'slow status advice when core.untrackedCache true, and fsmon
)
'
-test_expect_success EXPENSIVE 'status does not re-read unchanged 4 or 8 GiB file' '
+test_expect_success EXPENSIVE,SIZE_T_IS_64BIT 'status does not re-read unchanged 4 or 8 GiB file' '
(
mkdir large-file &&
cd large-file &&
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH 6/9] t7900: clean up large EXPENSIVE repository
From: Patrick Steinhardt @ 2026-07-02 12:00 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Johannes Schindelin
In-Reply-To: <20260702-b4-pks-t-fixes-for-GIT-TEST-LONG-v1-0-76b4d7bab3d0@pks.im>
One of the tests in t7900 is marked with EXPENSIVE because we create a
repository with 2GB of data that we end up repacking. We never clean up
that repository though, so we occupy the full 2GB of data until the end
of the test suite. Besides clogging our disk, it also means that all
subsequent tests may have to repack this data multiple times.
Adapt the test so that we create the data in a standalone repository
that we clean up at the end of the test. While at it, also disable
auto-maintenance so that it does not race with our manual maintenance.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
t/t7900-maintenance.sh | 56 ++++++++++++++++++++++++++++----------------------
1 file changed, 31 insertions(+), 25 deletions(-)
diff --git a/t/t7900-maintenance.sh b/t/t7900-maintenance.sh
index d7f82e1bec..8a7e1306d0 100755
--- a/t/t7900-maintenance.sh
+++ b/t/t7900-maintenance.sh
@@ -461,36 +461,42 @@ test_expect_success 'incremental-repack task' '
'
test_expect_success EXPENSIVE 'incremental-repack 2g limit' '
- test_config core.compression 0 &&
+ test_when_finished rm -rf expensive-repo &&
+ git init expensive-repo &&
+ (
+ cd expensive-repo &&
+ git config set core.compression 0 &&
+ git config set maintenance.auto false &&
- for i in $(test_seq 1 5)
- do
- test-tool genrandom foo$i $((512 * 1024 * 1024 + 1)) >>big ||
- return 1
- done &&
- git add big &&
- git commit -qm "Add big file (1)" &&
+ for i in $(test_seq 1 5)
+ do
+ test-tool genrandom foo$i $((512 * 1024 * 1024 + 1)) >>big ||
+ return 1
+ done &&
+ git add big &&
+ git commit -qm "Add big file (1)" &&
- # ensure any possible loose objects are in a pack-file
- git maintenance run --task=loose-objects &&
+ # ensure any possible loose objects are in a pack-file
+ git maintenance run --task=loose-objects &&
- rm big &&
- for i in $(test_seq 6 10)
- do
- test-tool genrandom foo$i $((512 * 1024 * 1024 + 1)) >>big ||
- return 1
- done &&
- git add big &&
- git commit -qm "Add big file (2)" &&
+ rm big &&
+ for i in $(test_seq 6 10)
+ do
+ test-tool genrandom foo$i $((512 * 1024 * 1024 + 1)) >>big ||
+ return 1
+ done &&
+ git add big &&
+ git commit -qm "Add big file (2)" &&
- # ensure any possible loose objects are in a pack-file
- git maintenance run --task=loose-objects &&
+ # ensure any possible loose objects are in a pack-file
+ git maintenance run --task=loose-objects &&
- # Now run the incremental-repack task and check the batch-size
- GIT_TRACE2_EVENT="$(pwd)/run-2g.txt" git maintenance run \
- --task=incremental-repack 2>/dev/null &&
- test_subcommand git multi-pack-index repack \
- --no-progress --batch-size=2147483647 <run-2g.txt
+ # Now run the incremental-repack task and check the batch-size
+ GIT_TRACE2_EVENT="$(pwd)/run-2g.txt" git maintenance run \
+ --task=incremental-repack 2>/dev/null &&
+ test_subcommand git multi-pack-index repack \
+ --no-progress --batch-size=2147483647 <run-2g.txt
+ )
'
run_incremental_repack_and_verify () {
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH 7/9] t: use `test_bool_env` to parse GIT_TEST_LONG
From: Patrick Steinhardt @ 2026-07-02 12:01 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Johannes Schindelin
In-Reply-To: <20260702-b4-pks-t-fixes-for-GIT-TEST-LONG-v1-0-76b4d7bab3d0@pks.im>
It's currently hard to explicitly disable GIT_TEST_LONG by setting it to
`false`. Fix this by using `test_bool_env` instead.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
ci/lib.sh | 2 +-
t/test-lib.sh | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/ci/lib.sh b/ci/lib.sh
index b939110a6e..01a0bc6b75 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -321,7 +321,7 @@ export SKIP_DASHED_BUILT_INS=YesPlease
# enable the long tests for pushes to the integration branches as well.
case "$GITHUB_EVENT_NAME,$CI_BRANCH" in
pull_request,*|push,*next*|push,*master*|push,*main*|push,*maint*)
- export GIT_TEST_LONG=YesPlease
+ export GIT_TEST_LONG=true
;;
esac
diff --git a/t/test-lib.sh b/t/test-lib.sh
index ceefb99bff..623fcfb747 100644
--- a/t/test-lib.sh
+++ b/t/test-lib.sh
@@ -210,7 +210,7 @@ parse_option () {
-i|--i|--im|--imm|--imme|--immed|--immedi|--immedia|--immediat|--immediate)
immediate=t ;;
-l|--l|--lo|--lon|--long|--long-|--long-t|--long-te|--long-tes|--long-test|--long-tests)
- GIT_TEST_LONG=t; export GIT_TEST_LONG ;;
+ GIT_TEST_LONG=true; export GIT_TEST_LONG ;;
-r)
mark_option_requires_arg "$opt" run_list
;;
@@ -1849,7 +1849,7 @@ test_lazy_prereq AUTOIDENT '
'
test_lazy_prereq EXPENSIVE '
- test -n "$GIT_TEST_LONG"
+ test_bool_env GIT_TEST_LONG false
'
test_lazy_prereq EXPENSIVE_ON_WINDOWS '
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH 8/9] gitlab-ci: disable RAM disk on macOS jobs
From: Patrick Steinhardt @ 2026-07-02 12:01 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Johannes Schindelin
In-Reply-To: <20260702-b4-pks-t-fixes-for-GIT-TEST-LONG-v1-0-76b4d7bab3d0@pks.im>
When we added the macOS jobs to GitLab CI in 56090a35ab (ci: add macOS
jobs to GitLab CI, 2024-01-18) we had to work around some very slow
disks. This workaround essentially creates a RAM disk that we mount,
where all test data is being written into RAM instead of the real disk.
In the next commit though we're about to enable "GIT_TEST_LONG", which
will make tests run that are marked with the "EXPENSIVE" prerequisite.
This change will make a couple of tests run that write up to 8GB of data
into the test output directory. As our RAM disk is only 4GB in size,
this change will cause ENOSPC errors.
We could accommodate for this by increasing the size of the RAM disk.
In c9d708b7fc (gitlab-ci: upgrade macOS runners, 2026-05-21) we have
upgraded our runners to use the "large" runners, which have 16GB of RAM
available. So we could easily expand the RAM disk to a capacity of for
example 12GB. But some test runs have shown that this is still quite
flaky overall, as we get quite close to our limits.
Instead, drop the workaround completely. This does indeed slow down
execution of the test jobs:
- osx-clang goes from 18 minutes to 25 minutes
- osx-meson goes from 21 minutes to 33 minutes
- osx-reftable stays at 21 minutes
The last one seems like an outlier. The only explanation that I have is
that we end up writing significantly less files with the reftable
backend, which ultimately causes less I/O.
Overall though, it's preferable to have something that works with the
least amount of flakiness compared to having something else that is
faster but unstable. Despite that, the macOS jobs aren't even the
slowest jobs, so this doesn't extend the overall pipeline's length.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
.gitlab-ci.yml | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 1a8e90932c..a4aebe8b71 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -88,13 +88,8 @@ test:osx:
tags:
- saas-macos-large-m2pro
variables:
- TEST_OUTPUT_DIRECTORY: "/Volumes/RAMDisk"
+ TEST_OUTPUT_DIRECTORY: "/tmp/test-output"
before_script:
- # Create a 4GB RAM disk that we use to store test output on. This small hack
- # significantly speeds up tests by more than a factor of 2 because the
- # macOS runners use network-attached storage as disks, which is _really_
- # slow with the many small writes that our tests do.
- - sudo diskutil apfs create $(hdiutil attach -nomount ram://8192000) RAMDisk
- ./ci/install-dependencies.sh
script:
- ./ci/run-build-and-tests.sh
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH 9/9] gitlab-ci: enable "GIT_TEST_LONG"
From: Patrick Steinhardt @ 2026-07-02 12:01 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Johannes Schindelin
In-Reply-To: <20260702-b4-pks-t-fixes-for-GIT-TEST-LONG-v1-0-76b4d7bab3d0@pks.im>
Starting with 7a094d68a2 (ci: run expensive tests on push builds to
integration branches, 2026-05-08) we run expensive tests in our CI for
certain events. So far, this has only been wired up for GitHub Workflows
though, which creates a test gap for GitLab CI.
Plug this gap by also making this work for the latter.
Note that these tests cannot be run on the Windows runners, as they only
have 7.5GB of RAM. This is insufficient for some of the EXPENSIVE tests,
so we explicitly disable "GIT_TEST_LONG" on these jobs.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
.gitlab-ci.yml | 6 ++++++
ci/lib.sh | 12 ++++++++++--
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index a4aebe8b71..1c4d04da9d 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -147,6 +147,9 @@ test:mingw64:
needs:
- job: "build:mingw64"
artifacts: true
+ variables:
+ # Windows runners don't have enough RAM to run EXPENSIVE tests.
+ GIT_TEST_LONG: false
before_script:
- *windows_before_script
- git-sdk/usr/bin/bash.exe -l -c 'tar xf artifacts/artifacts.tar.gz'
@@ -195,6 +198,9 @@ test:msvc-meson:
script:
- |
& "C:/Program Files/Git/usr/bin/bash.exe" -l -c 'ci/run-test-slice-meson.sh build $CI_NODE_INDEX $CI_NODE_TOTAL'
+ variables:
+ # Windows runners don't have enough RAM to run EXPENSIVE tests.
+ GIT_TEST_LONG: false
after_script:
- |
if ($env:CI_JOB_STATUS -ne "success") {
diff --git a/ci/lib.sh b/ci/lib.sh
index 01a0bc6b75..6c52154eac 100755
--- a/ci/lib.sh
+++ b/ci/lib.sh
@@ -215,6 +215,7 @@ then
test macos != "$CI_OS_NAME" || CI_OS_NAME=osx
CI_REPO_SLUG="$GITHUB_REPOSITORY"
CI_JOB_ID="$GITHUB_RUN_ID"
+ CI_EVENT="$GITHUB_EVENT_NAME"
CC="${CC_PACKAGE:-${CC:-gcc}}"
DONT_SKIP_TAGS=t
handle_failed_tests () {
@@ -239,6 +240,13 @@ then
CI_BRANCH="$CI_COMMIT_REF_NAME"
CI_COMMIT="$CI_COMMIT_SHA"
+ case "$CI_PIPELINE_SOURCE" in
+ merge_request_event)
+ CI_EVENT=pull_request;;
+ *)
+ CI_EVENT="$CI_PIPELINE_SOURCE";;
+ esac
+
case "$OS,$CI_JOB_IMAGE" in
Windows_NT,*)
CI_OS_NAME=windows
@@ -319,9 +327,9 @@ export SKIP_DASHED_BUILT_INS=YesPlease
# enable "expensive" tests for PR events.
# In order to catch bugs introduced at integration time by mismerges,
# enable the long tests for pushes to the integration branches as well.
-case "$GITHUB_EVENT_NAME,$CI_BRANCH" in
+case "$CI_EVENT,$CI_BRANCH" in
pull_request,*|push,*next*|push,*master*|push,*main*|push,*maint*)
- export GIT_TEST_LONG=true
+ export GIT_TEST_LONG=${GIT_TEST_LONG:-true}
;;
esac
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH v2 0/6] odb: refactor source-specific information in object info
From: Patrick Steinhardt @ 2026-07-02 12:01 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Justin Tobler
In-Reply-To: <20260624-b4-pks-odb-drop-whence-v1-0-8d1877b790ac@pks.im>
Hi,
this patch series refactors `struct object_info` to not contain the
`whence` field anymore.
This field only gave the caller information about the type of source
this was read from, but it didn't allow them to figure out which source
specifically yielded the object. So instead, we replace this information
with a new `struct odb_source_info` field that both contains info about
the source, and any backend-specific data.
With this in place we can re-query the same backend for any given
object. More importantly though, we can eventually also use the backend-
specific data to also uniquely identify any given object, e.g. by
recording the packfile and offset, so that we can even yield the same
object in case one source contains the object multiple times.
Furthermore, with this change all information in `struct object_info` is
now following the same request-response-field style.
The series is built on top of 26d8d94e94 (A few more topics before -rc2,
2026-06-21) with ps/odb-source-packed at 1bba3c035d (odb/source-packed:
drop pointer to "files" parent source, 2026-06-17) merged into it.
Changes in v2:
- Rename `struct object_info_source` to `odb_source_info` and the
`sourcep` pointer to `source_infop`. This follows a suggestion made
by Justin, as the current naming is too easy to confuse with the
actual source.
- Link to v1: https://patch.msgid.link/20260624-b4-pks-odb-drop-whence-v1-0-8d1877b790ac@pks.im
Thanks!
Patrick
---
Patrick Steinhardt (6):
packfile: thread odb_source_packed through packed_object_info()
odb: make backend-specific fields optional
odb: add `source` field to struct object_info_source
treewide: convert users of `whence` to the new source field
odb: drop `whence` field from object info
odb: document object info fields
builtin/cat-file.c | 12 +++++---
builtin/index-pack.c | 9 ++++--
builtin/pack-objects.c | 19 ++++++++----
commit-graph.c | 2 +-
odb.c | 4 +--
odb.h | 80 +++++++++++++++++++++++++++++++++++---------------
odb/source-inmemory.c | 3 +-
odb/source-loose.c | 4 +--
odb/source-packed.c | 4 +--
pack-bitmap.c | 2 +-
packfile.c | 45 ++++++++++++++++------------
packfile.h | 6 ++--
reachable.c | 7 +++--
t/helper/test-bitmap.c | 2 +-
14 files changed, 130 insertions(+), 69 deletions(-)
Range-diff versus v1:
1: 52cf49cd37 = 1: 19c247567e packfile: thread odb_source_packed through packed_object_info()
2: 325878ed04 = 2: 084c3592b4 odb: make backend-specific fields optional
3: cb7f9154b6 < -: ---------- odb: add `source` field to struct object_info_source
4: 63d2eb7b7c < -: ---------- treewide: convert users of `whence` to the new source field
-: ---------- > 3: dc878542bf odb: add `source` field to struct object_info_source
-: ---------- > 4: d2e2b90842 treewide: convert users of `whence` to the new source field
5: 332899f012 ! 5: 7e09bc6aa9 odb: drop `whence` field from object info
@@ odb.c: static int oid_object_info_convert(struct repository *r,
}
}
- input_oi->whence = new_oi.whence;
- if (input_oi->sourcep)
- *input_oi->sourcep = *new_oi.sourcep;
+ if (input_oi->source_infop)
+ *input_oi->source_infop = *new_oi.source_infop;
return ret;
## odb.h ##
@@ odb.h: struct object_info {
* or multiple times in the same source.
*/
- struct object_info_source *sourcep;
+ struct odb_source_info *source_infop;
-
- /* Response */
- enum {
@@ odb.h: struct object_info {
## odb/source-inmemory.c ##
@@ odb/source-inmemory.c: static void populate_object_info(struct odb_source_inmemory *source,
*oi->mtimep = 0;
- if (oi->sourcep)
- oi->sourcep->source = &source->base;
+ if (oi->source_infop)
+ oi->source_infop->source = &source->base;
-
- oi->whence = OI_CACHED;
}
@@ odb/source-inmemory.c: static void populate_object_info(struct odb_source_inmemo
## odb/source-loose.c ##
@@ odb/source-loose.c: static int read_object_info_from_path(struct odb_source_loose *loose,
oidclr(oi->delta_base_oid, loose->base.odb->repo->hash_algo);
- if (oi->sourcep && !ret)
- oi->sourcep->source = &loose->base;
+ if (oi->source_infop && !ret)
+ oi->source_infop->source = &loose->base;
- if (!ret)
- oi->whence = OI_LOOSE;
}
@@ packfile.c: int packed_object_info_with_index_pos(struct odb_source_packed *sour
- oi->whence = OI_PACKED;
-
- if (oi->sourcep) {
+ if (oi->source_infop) {
if (!source)
BUG("cannot request source without an owning source");
6: 1e79d64921 ! 6: 1c25e56d0b odb: document object info fields
@@ Commit message
Signed-off-by: Patrick Steinhardt <ps@pks.im>
## odb.h ##
-@@ odb.h: struct object_info_source {
+@@ odb.h: struct odb_source_info {
} u;
};
---
base-commit: 969dbd51a70f9105ee9965adec5c5a02e75ab5b3
change-id: 20260612-b4-pks-odb-drop-whence-1b0af9ab16f4
^ permalink raw reply
* [PATCH v2 1/6] packfile: thread odb_source_packed through packed_object_info()
From: Patrick Steinhardt @ 2026-07-02 12:01 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Justin Tobler
In-Reply-To: <20260702-b4-pks-odb-drop-whence-v2-0-b0af7468ad95@pks.im>
Add an optional `struct odb_source_packed *source` parameter to
`packed_object_info()` and `packed_object_info_with_index_pos()`. This
parameter is unused at this point in time, but it will be used in a
follow-up commit so that we can record the source of a specific object.
Note that callers in "odb/source-packed.c" pass the already-available
source, but all other callers pass `NULL` instead. This is fine though,
as we only care about populating this info when called via the packed
store.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
builtin/cat-file.c | 2 +-
builtin/pack-objects.c | 4 ++--
commit-graph.c | 2 +-
odb/source-packed.c | 4 ++--
pack-bitmap.c | 2 +-
packfile.c | 8 +++++---
packfile.h | 6 ++++--
t/helper/test-bitmap.c | 2 +-
8 files changed, 17 insertions(+), 13 deletions(-)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 0f3dbd9850..8726485f1f 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -497,7 +497,7 @@ static void batch_object_write(const char *obj_name,
data->info.sizep = &data->size;
if (pack)
- ret = packed_object_info(pack, offset, &data->info);
+ ret = packed_object_info(NULL, pack, offset, &data->info);
else
ret = odb_read_object_info_extended(the_repository->objects,
&data->oid, &data->info,
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index bc5f9ef321..620d9ce085 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -2463,7 +2463,7 @@ static void drop_reused_delta(struct object_entry *entry)
oi.sizep = &size;
oi.typep = &type;
- if (packed_object_info(IN_PACK(entry), entry->in_pack_offset, &oi) < 0) {
+ if (packed_object_info(NULL, IN_PACK(entry), entry->in_pack_offset, &oi) < 0) {
/*
* We failed to get the info from this pack for some reason;
* fall back to odb_read_object_info, which may find another copy.
@@ -3804,7 +3804,7 @@ static int add_object_entry_from_pack(const struct object_id *oid,
ofs = nth_packed_object_offset(p, pos);
oi.typep = &type;
- if (packed_object_info(p, ofs, &oi) < 0) {
+ if (packed_object_info(NULL, p, ofs, &oi) < 0) {
die(_("could not get type of object %s in pack %s"),
oid_to_hex(oid), p->pack_name);
} else if (type == OBJ_COMMIT) {
diff --git a/commit-graph.c b/commit-graph.c
index c6d9c5c740..9dc8bd5eee 100644
--- a/commit-graph.c
+++ b/commit-graph.c
@@ -1538,7 +1538,7 @@ static int add_packed_commits(const struct object_id *oid,
struct object_info oi = OBJECT_INFO_INIT;
oi.typep = &type;
- if (packed_object_info(pack, offset, &oi) < 0)
+ if (packed_object_info(NULL, pack, offset, &oi) < 0)
die(_("unable to get type of object %s"), oid_to_hex(oid));
return add_packed_commits_oi(oid, &oi, data);
diff --git a/odb/source-packed.c b/odb/source-packed.c
index 42c28fba0e..43fb53b72d 100644
--- a/odb/source-packed.c
+++ b/odb/source-packed.c
@@ -59,7 +59,7 @@ static int odb_source_packed_read_object_info(struct odb_source *source,
if (!oi)
return 0;
- ret = packed_object_info(e.p, e.offset, oi);
+ ret = packed_object_info(packed, e.p, e.offset, oi);
if (ret < 0) {
mark_bad_packed_object(e.p, oid);
return -1;
@@ -99,7 +99,7 @@ static int odb_source_packed_for_each_object_wrapper(const struct object_id *oid
off_t offset = nth_packed_object_offset(pack, index_pos);
struct object_info oi = *data->request;
- if (packed_object_info_with_index_pos(pack, offset,
+ if (packed_object_info_with_index_pos(data->store, pack, offset,
&index_pos, &oi) < 0) {
mark_bad_packed_object(pack, oid);
return -1;
diff --git a/pack-bitmap.c b/pack-bitmap.c
index 83eb47a28b..35774b6f0c 100644
--- a/pack-bitmap.c
+++ b/pack-bitmap.c
@@ -1877,7 +1877,7 @@ static unsigned long get_size_by_pos(struct bitmap_index *bitmap_git,
ofs = pack_pos_to_offset(pack, pos);
}
- if (packed_object_info(pack, ofs, &oi) < 0) {
+ if (packed_object_info(NULL, pack, ofs, &oi) < 0) {
struct object_id oid;
nth_bitmap_object_oid(bitmap_git, &oid,
pack_pos_to_index(pack, pos));
diff --git a/packfile.c b/packfile.c
index 1d1b23b6cc..2b741d7a76 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1324,7 +1324,8 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
hashmap_add(&delta_base_cache, &ent->ent);
}
-int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset,
+int packed_object_info_with_index_pos(struct odb_source_packed *source UNUSED,
+ struct packed_git *p, off_t obj_offset,
uint32_t *maybe_index_pos, struct object_info *oi)
{
struct pack_window *w_curs = NULL;
@@ -1446,10 +1447,11 @@ int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset,
return ret;
}
-int packed_object_info(struct packed_git *p, off_t obj_offset,
+int packed_object_info(struct odb_source_packed *source,
+ struct packed_git *p, off_t obj_offset,
struct object_info *oi)
{
- return packed_object_info_with_index_pos(p, obj_offset, NULL, oi);
+ return packed_object_info_with_index_pos(source, p, obj_offset, NULL, oi);
}
static void *unpack_compressed_entry(struct packed_git *p,
diff --git a/packfile.h b/packfile.h
index 2329a69701..e1f77152b5 100644
--- a/packfile.h
+++ b/packfile.h
@@ -320,9 +320,11 @@ extern int do_check_packed_object_crc;
* Look up the object info for a specific offset in the packfile.
* Returns zero on success, a negative error code otherwise.
*/
-int packed_object_info(struct packed_git *pack,
+int packed_object_info(struct odb_source_packed *source,
+ struct packed_git *pack,
off_t offset, struct object_info *);
-int packed_object_info_with_index_pos(struct packed_git *p, off_t obj_offset,
+int packed_object_info_with_index_pos(struct odb_source_packed *source,
+ struct packed_git *p, off_t obj_offset,
uint32_t *maybe_index_pos, struct object_info *oi);
void mark_bad_packed_object(struct packed_git *, const struct object_id *);
diff --git a/t/helper/test-bitmap.c b/t/helper/test-bitmap.c
index b130832b81..8547ef67e2 100644
--- a/t/helper/test-bitmap.c
+++ b/t/helper/test-bitmap.c
@@ -52,7 +52,7 @@ static int add_packed_object(const struct object_id *oid,
entry = packlist_alloc(packed, oid);
entry->idx.offset = nth_packed_object_offset(pack, pos);
- if (packed_object_info(pack, entry->idx.offset, &oi) < 0)
+ if (packed_object_info(NULL, pack, entry->idx.offset, &oi) < 0)
die("could not get type of object %s",
oid_to_hex(oid));
oe_set_type(entry, type);
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH v2 2/6] odb: make backend-specific fields optional
From: Patrick Steinhardt @ 2026-07-02 12:02 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Justin Tobler
In-Reply-To: <20260702-b4-pks-odb-drop-whence-v2-0-b0af7468ad95@pks.im>
The `struct object_info` carries two pieces of information
about how an object was looked up:
- The `whence` enum identifying the backend.
- The backend-tagged union `u` exposing backend-specific details
(currently only the packed-source case, which records the owning
pack, offset and packed object type).
The union is populated unconditionally, even though most callers don't
care about provenance at all.
Split the backend-specific union out into a new public type, `struct
object_info_source`, and make the object info structure carry it via
just another opt-in request pointer. As with all the other requestable
information, callers that need source info allocate a `struct
object_info_source` on the stack and point `sourcep` at it; callers that
don't care about it simply leave the field as a `NULL` pointer. Adapt
callers accordingly.
Note that the `whence` enum is strictly-speaking also backend-specific
information, so it would be another good candidate to be moved into the
`struct object_info_source`. For now though it is left alone, as it will
be replaced by a `struct odb_source` pointer in a subsequent commit.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
builtin/cat-file.c | 8 +++++--
builtin/index-pack.c | 8 +++++--
builtin/pack-objects.c | 15 +++++++++----
odb.c | 3 ++-
odb.h | 60 +++++++++++++++++++++++++++++++++-----------------
packfile.c | 33 ++++++++++++++-------------
reachable.c | 5 ++++-
7 files changed, 87 insertions(+), 45 deletions(-)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 8726485f1f..adc626ce30 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -835,7 +835,8 @@ static int batch_one_object_oi(const struct object_id *oid,
{
struct for_each_object_payload *payload = _payload;
if (oi && oi->whence == OI_PACKED)
- return payload->callback(oid, oi->u.packed.pack, oi->u.packed.offset,
+ return payload->callback(oid, oi->sourcep->u.packed.pack,
+ oi->sourcep->u.packed.offset,
payload->payload);
return payload->callback(oid, NULL, 0, payload->payload);
}
@@ -906,7 +907,10 @@ static void batch_each_object(struct batch_options *opt,
&payload, flags);
}
} else {
- struct object_info oi = { 0 };
+ struct object_info_source oi_source;
+ struct object_info oi = {
+ .sourcep = &oi_source,
+ };
for (source = the_repository->objects->sources; source; source = source->next) {
struct odb_source_files *files = odb_source_files_downcast(source);
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index f396658468..77af26db8f 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1825,11 +1825,15 @@ static void repack_local_links(void)
oidset_iter_init(&outgoing_links, &iter);
while ((oid = oidset_iter_next(&iter))) {
- struct object_info info = OBJECT_INFO_INIT;
+ struct object_info_source info_source;
+ struct object_info info = {
+ .sourcep = &info_source,
+ };
+
if (odb_read_object_info_extended(the_repository->objects, oid, &info, 0))
/* Missing; assume it is a promisor object */
continue;
- if (info.whence == OI_PACKED && info.u.packed.pack->pack_promisor)
+ if (info.whence == OI_PACKED && info_source.u.packed.pack->pack_promisor)
continue;
if (!cmd.args.nr) {
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 620d9ce085..9deb37e9e8 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -4491,8 +4491,9 @@ static int add_object_in_unpacked_pack(const struct object_id *oid,
void *data UNUSED)
{
if (cruft) {
- add_cruft_object_entry(oid, OBJ_NONE, oi->u.packed.pack,
- oi->u.packed.offset, NULL, *oi->mtimep);
+ add_cruft_object_entry(oid, OBJ_NONE, oi->sourcep->u.packed.pack,
+ oi->sourcep->u.packed.offset, NULL,
+ *oi->mtimep);
} else {
add_object_entry(oid, OBJ_NONE, "", 0);
}
@@ -4509,8 +4510,10 @@ static void add_objects_in_unpacked_packs(void)
ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS,
};
+ struct object_info_source oi_source;
struct object_info oi = {
.mtimep = &mtime,
+ .sourcep = &oi_source,
};
odb_prepare_alternates(to_pack.repo->objects);
@@ -5000,10 +5003,14 @@ static int option_parse_cruft_expiration(const struct option *opt UNUSED,
static int is_not_in_promisor_pack_obj(struct object *obj, void *data UNUSED)
{
- struct object_info info = OBJECT_INFO_INIT;
+ struct object_info_source info_source;
+ struct object_info info = {
+ .sourcep = &info_source,
+ };
+
if (odb_read_object_info_extended(the_repository->objects, &obj->oid, &info, 0))
BUG("should_include_obj should only be called on existing objects");
- return info.whence != OI_PACKED || !info.u.packed.pack->pack_promisor;
+ return info.whence != OI_PACKED || !info_source.u.packed.pack->pack_promisor;
}
static int is_not_in_promisor_pack(struct commit *commit, void *data) {
diff --git a/odb.c b/odb.c
index 7d555be09f..99f4e7551c 100644
--- a/odb.c
+++ b/odb.c
@@ -692,7 +692,8 @@ static int oid_object_info_convert(struct repository *r,
}
}
input_oi->whence = new_oi.whence;
- input_oi->u = new_oi.u;
+ if (input_oi->sourcep)
+ *input_oi->sourcep = *new_oi.sourcep;
return ret;
}
diff --git a/odb.h b/odb.h
index 3834a0dcbf..770900289a 100644
--- a/odb.h
+++ b/odb.h
@@ -248,6 +248,38 @@ int odb_pretend_object(struct object_database *odb,
void *buf, size_t len, enum object_type type,
struct object_id *oid);
+/*
+ * Object information that can be used to uniquely identify an object and learn
+ * more about how exactly it is stored.
+ */
+struct object_info_source {
+ /*
+ * Backend-specific information about the specific object. This can be
+ * used for example to uniquely identify a given object in case it
+ * exists multiple times.
+ */
+ union {
+ /*
+ * struct {
+ * ... Nothing to expose in this case
+ * } cached;
+ * struct {
+ * ... Nothing to expose in this case
+ * } loose;
+ */
+ struct {
+ struct packed_git *pack;
+ off_t offset;
+ enum packed_object_type {
+ PACKED_OBJECT_TYPE_UNKNOWN,
+ PACKED_OBJECT_TYPE_FULL,
+ PACKED_OBJECT_TYPE_OFS_DELTA,
+ PACKED_OBJECT_TYPE_REF_DELTA,
+ } type;
+ } packed;
+ } u;
+};
+
struct object_info {
/* Request */
enum object_type *typep;
@@ -269,32 +301,20 @@ struct object_info {
*/
time_t *mtimep;
+ /*
+ * Backend-specific information that tells the caller where exactly an
+ * object was looked up from. This information should help disambiguate
+ * object lookups in case the same object exists in multiple sources,
+ * or multiple times in the same source.
+ */
+ struct object_info_source *sourcep;
+
/* Response */
enum {
OI_CACHED,
OI_LOOSE,
OI_PACKED,
} whence;
- union {
- /*
- * struct {
- * ... Nothing to expose in this case
- * } cached;
- * struct {
- * ... Nothing to expose in this case
- * } loose;
- */
- struct {
- struct packed_git *pack;
- off_t offset;
- enum packed_object_type {
- PACKED_OBJECT_TYPE_UNKNOWN,
- PACKED_OBJECT_TYPE_FULL,
- PACKED_OBJECT_TYPE_OFS_DELTA,
- PACKED_OBJECT_TYPE_REF_DELTA,
- } type;
- } packed;
- } u;
};
/*
diff --git a/packfile.c b/packfile.c
index 2b741d7a76..688c410b35 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1422,22 +1422,25 @@ int packed_object_info_with_index_pos(struct odb_source_packed *source UNUSED,
}
oi->whence = OI_PACKED;
- oi->u.packed.offset = obj_offset;
- oi->u.packed.pack = p;
- switch (type) {
- case OBJ_NONE:
- oi->u.packed.type = PACKED_OBJECT_TYPE_UNKNOWN;
- break;
- case OBJ_REF_DELTA:
- oi->u.packed.type = PACKED_OBJECT_TYPE_REF_DELTA;
- break;
- case OBJ_OFS_DELTA:
- oi->u.packed.type = PACKED_OBJECT_TYPE_OFS_DELTA;
- break;
- default:
- oi->u.packed.type = PACKED_OBJECT_TYPE_FULL;
- break;
+ if (oi->sourcep) {
+ oi->sourcep->u.packed.offset = obj_offset;
+ oi->sourcep->u.packed.pack = p;
+
+ switch (type) {
+ case OBJ_NONE:
+ oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_UNKNOWN;
+ break;
+ case OBJ_REF_DELTA:
+ oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_REF_DELTA;
+ break;
+ case OBJ_OFS_DELTA:
+ oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_OFS_DELTA;
+ break;
+ default:
+ oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_FULL;
+ break;
+ }
}
ret = 0;
diff --git a/reachable.c b/reachable.c
index 101cfc2727..2fc5b82d62 100644
--- a/reachable.c
+++ b/reachable.c
@@ -235,7 +235,8 @@ static int add_recent_object(const struct object_id *oid,
add_pending_object(data->revs, obj, "");
if (data->cb) {
if (oi->whence == OI_PACKED)
- data->cb(obj, oi->u.packed.pack, oi->u.packed.offset, *oi->mtimep);
+ data->cb(obj, oi->sourcep->u.packed.pack,
+ oi->sourcep->u.packed.offset, *oi->mtimep);
else
data->cb(obj, NULL, 0, *oi->mtimep);
}
@@ -252,9 +253,11 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,
unsigned flags;
enum object_type type;
time_t mtime;
+ struct object_info_source oi_source;
struct object_info oi = {
.mtimep = &mtime,
.typep = &type,
+ .sourcep = &oi_source,
};
int r;
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH v2 3/6] odb: add `source` field to struct object_info_source
From: Patrick Steinhardt @ 2026-07-02 12:02 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Justin Tobler
In-Reply-To: <20260702-b4-pks-odb-drop-whence-v2-0-b0af7468ad95@pks.im>
The previous commit introduced `struct object_info_source` as an opt-in
container for backend-specific information, but for now we only moved
preexisting data into this structure. Most importantly, the caller has
no way yet to learn about which source an object was actually looked up
from. Instead, callers have to rely on the `whence` enum to distinguish
the object type, but cannot use that enum to tell the object source.
Add a `struct odb_source *source` field to the structure and populate it
from each backend's lookup path.
The `whence` enum is still set and used by callers; it will be removed
in a subsequent commit now that `sourcep->source` can identify the
backend on its own.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
builtin/cat-file.c | 8 ++++----
builtin/index-pack.c | 6 +++---
builtin/pack-objects.c | 14 +++++++-------
odb.c | 4 ++--
odb.h | 11 +++++++----
odb/source-inmemory.c | 3 +++
odb/source-loose.c | 2 ++
packfile.c | 20 ++++++++++++--------
reachable.c | 8 ++++----
9 files changed, 44 insertions(+), 32 deletions(-)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index adc626ce30..0aca6acb75 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -835,8 +835,8 @@ static int batch_one_object_oi(const struct object_id *oid,
{
struct for_each_object_payload *payload = _payload;
if (oi && oi->whence == OI_PACKED)
- return payload->callback(oid, oi->sourcep->u.packed.pack,
- oi->sourcep->u.packed.offset,
+ return payload->callback(oid, oi->source_infop->u.packed.pack,
+ oi->source_infop->u.packed.offset,
payload->payload);
return payload->callback(oid, NULL, 0, payload->payload);
}
@@ -907,9 +907,9 @@ static void batch_each_object(struct batch_options *opt,
&payload, flags);
}
} else {
- struct object_info_source oi_source;
+ struct odb_source_info source_info;
struct object_info oi = {
- .sourcep = &oi_source,
+ .source_infop = &source_info,
};
for (source = the_repository->objects->sources; source; source = source->next) {
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index 77af26db8f..fe6e70522d 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1825,15 +1825,15 @@ static void repack_local_links(void)
oidset_iter_init(&outgoing_links, &iter);
while ((oid = oidset_iter_next(&iter))) {
- struct object_info_source info_source;
+ struct odb_source_info source_info;
struct object_info info = {
- .sourcep = &info_source,
+ .source_infop = &source_info,
};
if (odb_read_object_info_extended(the_repository->objects, oid, &info, 0))
/* Missing; assume it is a promisor object */
continue;
- if (info.whence == OI_PACKED && info_source.u.packed.pack->pack_promisor)
+ if (info.whence == OI_PACKED && source_info.u.packed.pack->pack_promisor)
continue;
if (!cmd.args.nr) {
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index 9deb37e9e8..b7ef90f67c 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -4491,8 +4491,8 @@ static int add_object_in_unpacked_pack(const struct object_id *oid,
void *data UNUSED)
{
if (cruft) {
- add_cruft_object_entry(oid, OBJ_NONE, oi->sourcep->u.packed.pack,
- oi->sourcep->u.packed.offset, NULL,
+ add_cruft_object_entry(oid, OBJ_NONE, oi->source_infop->u.packed.pack,
+ oi->source_infop->u.packed.offset, NULL,
*oi->mtimep);
} else {
add_object_entry(oid, OBJ_NONE, "", 0);
@@ -4510,10 +4510,10 @@ static void add_objects_in_unpacked_packs(void)
ODB_FOR_EACH_OBJECT_SKIP_IN_CORE_KEPT_PACKS |
ODB_FOR_EACH_OBJECT_SKIP_ON_DISK_KEPT_PACKS,
};
- struct object_info_source oi_source;
+ struct odb_source_info source_info;
struct object_info oi = {
.mtimep = &mtime,
- .sourcep = &oi_source,
+ .source_infop = &source_info,
};
odb_prepare_alternates(to_pack.repo->objects);
@@ -5003,14 +5003,14 @@ static int option_parse_cruft_expiration(const struct option *opt UNUSED,
static int is_not_in_promisor_pack_obj(struct object *obj, void *data UNUSED)
{
- struct object_info_source info_source;
+ struct odb_source_info source_info;
struct object_info info = {
- .sourcep = &info_source,
+ .source_infop = &source_info,
};
if (odb_read_object_info_extended(the_repository->objects, &obj->oid, &info, 0))
BUG("should_include_obj should only be called on existing objects");
- return info.whence != OI_PACKED || !info_source.u.packed.pack->pack_promisor;
+ return info.whence != OI_PACKED || !source_info.u.packed.pack->pack_promisor;
}
static int is_not_in_promisor_pack(struct commit *commit, void *data) {
diff --git a/odb.c b/odb.c
index 99f4e7551c..34c35c47a5 100644
--- a/odb.c
+++ b/odb.c
@@ -692,8 +692,8 @@ static int oid_object_info_convert(struct repository *r,
}
}
input_oi->whence = new_oi.whence;
- if (input_oi->sourcep)
- *input_oi->sourcep = *new_oi.sourcep;
+ if (input_oi->source_infop)
+ *input_oi->source_infop = *new_oi.source_infop;
return ret;
}
diff --git a/odb.h b/odb.h
index 770900289a..659bf8afe1 100644
--- a/odb.h
+++ b/odb.h
@@ -249,10 +249,13 @@ int odb_pretend_object(struct object_database *odb,
struct object_id *oid);
/*
- * Object information that can be used to uniquely identify an object and learn
- * more about how exactly it is stored.
+ * Object database source information that can be used to uniquely identify an
+ * object and learn more about how exactly it is stored.
*/
-struct object_info_source {
+struct odb_source_info {
+ /* The source that this object has been looked up from. */
+ struct odb_source *source;
+
/*
* Backend-specific information about the specific object. This can be
* used for example to uniquely identify a given object in case it
@@ -307,7 +310,7 @@ struct object_info {
* object lookups in case the same object exists in multiple sources,
* or multiple times in the same source.
*/
- struct object_info_source *sourcep;
+ struct odb_source_info *source_infop;
/* Response */
enum {
diff --git a/odb/source-inmemory.c b/odb/source-inmemory.c
index e004566d76..1d173bfa46 100644
--- a/odb/source-inmemory.c
+++ b/odb/source-inmemory.c
@@ -52,6 +52,9 @@ static void populate_object_info(struct odb_source_inmemory *source,
*oi->contentp = xmemdupz(object->buf, object->size);
if (oi->mtimep)
*oi->mtimep = 0;
+ if (oi->source_infop)
+ oi->source_infop->source = &source->base;
+
oi->whence = OI_CACHED;
}
diff --git a/odb/source-loose.c b/odb/source-loose.c
index 66e6bb8d3f..c254957602 100644
--- a/odb/source-loose.c
+++ b/odb/source-loose.c
@@ -196,6 +196,8 @@ static int read_object_info_from_path(struct odb_source_loose *loose,
oi->typep = NULL;
if (oi->delta_base_oid)
oidclr(oi->delta_base_oid, loose->base.odb->repo->hash_algo);
+ if (oi->source_infop && !ret)
+ oi->source_infop->source = &loose->base;
if (!ret)
oi->whence = OI_LOOSE;
}
diff --git a/packfile.c b/packfile.c
index 688c410b35..ce51d1e5a3 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1324,7 +1324,7 @@ static void add_delta_base_cache(struct packed_git *p, off_t base_offset,
hashmap_add(&delta_base_cache, &ent->ent);
}
-int packed_object_info_with_index_pos(struct odb_source_packed *source UNUSED,
+int packed_object_info_with_index_pos(struct odb_source_packed *source,
struct packed_git *p, off_t obj_offset,
uint32_t *maybe_index_pos, struct object_info *oi)
{
@@ -1423,22 +1423,26 @@ int packed_object_info_with_index_pos(struct odb_source_packed *source UNUSED,
oi->whence = OI_PACKED;
- if (oi->sourcep) {
- oi->sourcep->u.packed.offset = obj_offset;
- oi->sourcep->u.packed.pack = p;
+ if (oi->source_infop) {
+ if (!source)
+ BUG("cannot request source without an owning source");
+ oi->source_infop->source = &source->base;
+
+ oi->source_infop->u.packed.offset = obj_offset;
+ oi->source_infop->u.packed.pack = p;
switch (type) {
case OBJ_NONE:
- oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_UNKNOWN;
+ oi->source_infop->u.packed.type = PACKED_OBJECT_TYPE_UNKNOWN;
break;
case OBJ_REF_DELTA:
- oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_REF_DELTA;
+ oi->source_infop->u.packed.type = PACKED_OBJECT_TYPE_REF_DELTA;
break;
case OBJ_OFS_DELTA:
- oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_OFS_DELTA;
+ oi->source_infop->u.packed.type = PACKED_OBJECT_TYPE_OFS_DELTA;
break;
default:
- oi->sourcep->u.packed.type = PACKED_OBJECT_TYPE_FULL;
+ oi->source_infop->u.packed.type = PACKED_OBJECT_TYPE_FULL;
break;
}
}
diff --git a/reachable.c b/reachable.c
index 2fc5b82d62..bf76b48fc5 100644
--- a/reachable.c
+++ b/reachable.c
@@ -235,8 +235,8 @@ static int add_recent_object(const struct object_id *oid,
add_pending_object(data->revs, obj, "");
if (data->cb) {
if (oi->whence == OI_PACKED)
- data->cb(obj, oi->sourcep->u.packed.pack,
- oi->sourcep->u.packed.offset, *oi->mtimep);
+ data->cb(obj, oi->source_infop->u.packed.pack,
+ oi->source_infop->u.packed.offset, *oi->mtimep);
else
data->cb(obj, NULL, 0, *oi->mtimep);
}
@@ -253,11 +253,11 @@ int add_unseen_recent_objects_to_traversal(struct rev_info *revs,
unsigned flags;
enum object_type type;
time_t mtime;
- struct object_info_source oi_source;
+ struct odb_source_info source_info;
struct object_info oi = {
.mtimep = &mtime,
.typep = &type,
- .sourcep = &oi_source,
+ .source_infop = &source_info,
};
int r;
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH v2 4/6] treewide: convert users of `whence` to the new source field
From: Patrick Steinhardt @ 2026-07-02 12:02 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Justin Tobler
In-Reply-To: <20260702-b4-pks-odb-drop-whence-v2-0-b0af7468ad95@pks.im>
The `whence` field has become redundant now that callers can learn about
the exact source an object has been looked up from via the `struct
object_info_source::source` field.
Adapt callers to use the new field. Note that all callsites already set
up the `info.sourcep` request pointer, so the conversion is rather
straight-forward.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
builtin/cat-file.c | 2 +-
builtin/index-pack.c | 3 ++-
builtin/pack-objects.c | 2 +-
reachable.c | 2 +-
4 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/builtin/cat-file.c b/builtin/cat-file.c
index 0aca6acb75..758f8fc736 100644
--- a/builtin/cat-file.c
+++ b/builtin/cat-file.c
@@ -834,7 +834,7 @@ static int batch_one_object_oi(const struct object_id *oid,
void *_payload)
{
struct for_each_object_payload *payload = _payload;
- if (oi && oi->whence == OI_PACKED)
+ if (oi && oi->source_infop->source->type == ODB_SOURCE_PACKED)
return payload->callback(oid, oi->source_infop->u.packed.pack,
oi->source_infop->u.packed.offset,
payload->payload);
diff --git a/builtin/index-pack.c b/builtin/index-pack.c
index fe6e70522d..7af1aea6f9 100644
--- a/builtin/index-pack.c
+++ b/builtin/index-pack.c
@@ -1833,7 +1833,8 @@ static void repack_local_links(void)
if (odb_read_object_info_extended(the_repository->objects, oid, &info, 0))
/* Missing; assume it is a promisor object */
continue;
- if (info.whence == OI_PACKED && source_info.u.packed.pack->pack_promisor)
+ if (source_info.source->type == ODB_SOURCE_PACKED &&
+ source_info.u.packed.pack->pack_promisor)
continue;
if (!cmd.args.nr) {
diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c
index b7ef90f67c..4fdb6dbf6f 100644
--- a/builtin/pack-objects.c
+++ b/builtin/pack-objects.c
@@ -5010,7 +5010,7 @@ static int is_not_in_promisor_pack_obj(struct object *obj, void *data UNUSED)
if (odb_read_object_info_extended(the_repository->objects, &obj->oid, &info, 0))
BUG("should_include_obj should only be called on existing objects");
- return info.whence != OI_PACKED || !source_info.u.packed.pack->pack_promisor;
+ return source_info.source->type != ODB_SOURCE_PACKED || !source_info.u.packed.pack->pack_promisor;
}
static int is_not_in_promisor_pack(struct commit *commit, void *data) {
diff --git a/reachable.c b/reachable.c
index bf76b48fc5..caadacc02a 100644
--- a/reachable.c
+++ b/reachable.c
@@ -234,7 +234,7 @@ static int add_recent_object(const struct object_id *oid,
add_pending_object(data->revs, obj, "");
if (data->cb) {
- if (oi->whence == OI_PACKED)
+ if (oi->source_infop->source->type == ODB_SOURCE_PACKED)
data->cb(obj, oi->source_infop->u.packed.pack,
oi->source_infop->u.packed.offset, *oi->mtimep);
else
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH v2 5/6] odb: drop `whence` field from object info
From: Patrick Steinhardt @ 2026-07-02 12:02 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Justin Tobler
In-Reply-To: <20260702-b4-pks-odb-drop-whence-v2-0-b0af7468ad95@pks.im>
In the preceding commits we have migrated all callers to derive their
information of how a specific object is stored to use the new object
info source instead, and hence the field is now unused. Drop it.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
odb.c | 1 -
odb.h | 7 -------
odb/source-inmemory.c | 2 --
odb/source-loose.c | 2 --
packfile.c | 2 --
5 files changed, 14 deletions(-)
diff --git a/odb.c b/odb.c
index 34c35c47a5..175a1ee42c 100644
--- a/odb.c
+++ b/odb.c
@@ -691,7 +691,6 @@ static int oid_object_info_convert(struct repository *r,
return -1;
}
}
- input_oi->whence = new_oi.whence;
if (input_oi->source_infop)
*input_oi->source_infop = *new_oi.source_infop;
return ret;
diff --git a/odb.h b/odb.h
index 659bf8afe1..c251788d50 100644
--- a/odb.h
+++ b/odb.h
@@ -311,13 +311,6 @@ struct object_info {
* or multiple times in the same source.
*/
struct odb_source_info *source_infop;
-
- /* Response */
- enum {
- OI_CACHED,
- OI_LOOSE,
- OI_PACKED,
- } whence;
};
/*
diff --git a/odb/source-inmemory.c b/odb/source-inmemory.c
index 1d173bfa46..460aec821c 100644
--- a/odb/source-inmemory.c
+++ b/odb/source-inmemory.c
@@ -54,8 +54,6 @@ static void populate_object_info(struct odb_source_inmemory *source,
*oi->mtimep = 0;
if (oi->source_infop)
oi->source_infop->source = &source->base;
-
- oi->whence = OI_CACHED;
}
static int odb_source_inmemory_read_object_info(struct odb_source *source,
diff --git a/odb/source-loose.c b/odb/source-loose.c
index c254957602..54df2e57d3 100644
--- a/odb/source-loose.c
+++ b/odb/source-loose.c
@@ -198,8 +198,6 @@ static int read_object_info_from_path(struct odb_source_loose *loose,
oidclr(oi->delta_base_oid, loose->base.odb->repo->hash_algo);
if (oi->source_infop && !ret)
oi->source_infop->source = &loose->base;
- if (!ret)
- oi->whence = OI_LOOSE;
}
return ret;
diff --git a/packfile.c b/packfile.c
index ce51d1e5a3..8fa6309a09 100644
--- a/packfile.c
+++ b/packfile.c
@@ -1421,8 +1421,6 @@ int packed_object_info_with_index_pos(struct odb_source_packed *source,
oidclr(oi->delta_base_oid, p->repo->hash_algo);
}
- oi->whence = OI_PACKED;
-
if (oi->source_infop) {
if (!source)
BUG("cannot request source without an owning source");
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* [PATCH v2 6/6] odb: document object info fields
From: Patrick Steinhardt @ 2026-07-02 12:02 UTC (permalink / raw)
To: git; +Cc: Junio C Hamano, Justin Tobler
In-Reply-To: <20260702-b4-pks-odb-drop-whence-v2-0-b0af7468ad95@pks.im>
Some of the fields in `struct object_info` are undocumented. Add these
missing comments.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
odb.h | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/odb.h b/odb.h
index c251788d50..a1e222f605 100644
--- a/odb.h
+++ b/odb.h
@@ -283,12 +283,28 @@ struct odb_source_info {
} u;
};
+/*
+ * The object info contains the query and response that is to be used for
+ * functions that end up reading object information. Callers are expected to
+ * populate pointers whose information they want to request.
+ */
struct object_info {
- /* Request */
+ /* The object type. */
enum object_type *typep;
+
+ /* The inflated object size in bytes. */
size_t *sizep;
+
+ /* The object size as stored on disk. */
off_t *disk_sizep;
+
+ /*
+ * The base the object is deltified against, in case it is stored as a
+ * delta.
+ */
struct object_id *delta_base_oid;
+
+ /* The object contents. Ownership of memory goes over to the caller. */
void **contentp;
/*
--
2.55.0.795.g602f6c329a.dirty
^ permalink raw reply related
* Re: [PATCH v5 0/4] history: add squash subcommand to fold a range
From: Patrick Steinhardt @ 2026-07-02 12:54 UTC (permalink / raw)
To: phillip.wood
Cc: Matt Hunter, Harald Nordgren, Harald Nordgren via GitGitGadget,
git
In-Reply-To: <3c35bd17-e884-432d-a400-36a89964ed89@gmail.com>
On Tue, Jun 30, 2026 at 03:01:43PM +0100, Phillip Wood wrote:
> On 30/06/2026 03:55, Matt Hunter wrote:
[?nip]
> > This is probably a larger question, since (according to the man page) it
> > affects the other 'git history' commands as well. When I run
> > 'git history ...' and discover that I made a mistake after inspecting
> > the results, is there a fool-proof way to undo the change and return to
> > the previous state? My first thought was to run 'git reset --hard ...',
> > but the default behavior of --update-refs (moving other branches) can
> > make this more complicated.
>
> Yes this is a problem to which we don't have a good solution at the moment.
> I believe Jujitsu and git-branchless both have some kind of operations log
> that lets you revert a whole operation rather than just a single ref-update.
> We'd need some way to tie all the ref updates from a single ref transaction
> together either by logging the separately or adding some form of transaction
> id to the reflog. That would be a big change.
Yeah, agreed. I think that the reflog is insufficient for a lot of Git's
operations and that it is way too hard to reason about. It's both too
detailed and not detailed enough at the same time:
- It provides way too much detail about individual reference updates
when all the user cares about is the high-level operation on the
logical level.
- It does not provide enough detail to give information about what the
high-level operation even was.
I don't think that we can fix the reflog to work properly in this case.
But I certainly think that we should explore whether we can eventually
introduce something like an oplog, as well, so that we can easily have
the equivalent of `jj undo`.
It's something that I'd eventually want to get to, but it'll take a
while. So if anybody else beats me to it then please go ahead :)
Patrick
^ permalink raw reply
* [ANNOUNCE] Git for Windows 2.55.0(2)
From: Johannes Schindelin @ 2026-07-02 13:46 UTC (permalink / raw)
To: git, git-packagers
Dear Git users,
Hot fix release for NTLM authentication issues! Git for Windows 2.55.0(2)
is available!
https://gitforwindows.org/
(Please note that NTLM support is scheduled to be dropped later this
year.)
Changes since Git for Windows v2.55.0 (June 29th 2026)
Following the MSYS2 project, on which Git for Windows is based, Windows
8.1 support will be dropped after Git for Windows v2.55.
Bug Fixes
* NTLM opt-in support, which had been prematurely disabled altogether
(a glimpse into this fall when NTLM will be disabled, no opt-in
possible) was fixed by temporarily enabling optional NTLM support
again.
Git-2.55.0.2-64-bit.exe | 74300da8dfe0d844c5449ffb809662f8eeac47916f83730c879c4084890c6c0e
Git-2.55.0.2-arm64.exe | 3df091fc297001ea9592554ee630111ea27b2d33b137859d08c4971abb319a7c
PortableGit-2.55.0.2-64-bit.7z.exe | b20d42da3afa228e9fa6174480de820282667e799440d655e308f700dfa0d0df
PortableGit-2.55.0.2-arm64.7z.exe | 65b913a56a62d7a91fc11a2eecb08422aaa34332d3b2ea39457d2eda02c2f99c
MinGit-2.55.0.2-64-bit.zip | e3ea2944cea4b3fabcd69c7c1669ef69b1b66c05ac7806d81224d0abad2dec31
MinGit-2.55.0.2-arm64.zip | 0b2b81fdce284efd174cbb51b886ccea2fd271679c4b5c21f07d9e03bae51413
MinGit-2.55.0.2-32-bit.zip | 04009f6150c1cec2d6779c51406c8c6a3f0133e57fa91c91eb8a030b93e68ccb
MinGit-2.55.0.2-busybox-64-bit.zip | 760e5a4d2ff5469adfc74f9f46901eee412de48dedaa6ef1785c0cf9a7f065fb
MinGit-2.55.0.2-busybox-32-bit.zip | cc4ce341dae51eafb6c30e0701569338b7cb32c0621328fe43db2047e8a8d821
Git-2.55.0.2-64-bit.tar.bz2 | 5cfd35fadb11ac2f629c16f7be262f3f138cfe3f368331ad1e44f9abb5814882
Git-2.55.0.2-arm64.tar.bz2 | 06c1c6c854628b9ac1081376bccc4a7b6ecd46ee14bb1bca10c57fa680234305
Ciao,
Johannes
^ permalink raw reply
* Re: [PATCH v5 0/4] history: add squash subcommand to fold a range
From: Phillip Wood @ 2026-07-02 13:58 UTC (permalink / raw)
To: Junio C Hamano
Cc: Harald Nordgren, phillip.wood, Patrick Steinhardt,
Harald Nordgren via GitGitGadget, git
In-Reply-To: <xmqqfr22obei.fsf@gitster.g>
On 01/07/2026 18:41, Junio C Hamano wrote:
> Phillip Wood <phillip.wood123@gmail.com> writes:
>
>> Yes - if you apply the way "rebase -i" works to multiple commits you can
>> end up with a message template that has a screen full of commented lines
>> between uncommitted parts of the message. See the example below from
>> earlier in the thread. It is not so much of a problem in "rebase -i"
>> because it only fixes up a single commit at a time so all the commented
>> messages end up at the top of the buffer and at worst you have a few "#
>> fixup! ..." or "# squash! ..." lines mixed in with the uncommitted text.
>>
>> # This is the combination of 4 commits
>> # This is the first commit message
>> Base subject
>>
>> Base body
>>
>> # This is the second commit message
>> # Another subject
>>
>> # Another body
>>
>> # This is the third commit message
>> # fixup! Base subject
>>
>> # This is the fourth commit message
>> # amend! Another subject
>> A better subject
>>
>> A better body
>
> In the example, the second one becomes completely empty?
Yes because there is an amend! commit that replaces its message
> Is the proposal not to show any messages that will be discarded
> anyway and not even show them in commented form? I think that makes
> sense, and leaving only commit titles for these commits that would
> not contribute to the text in the editor given to the user to edit
> would indeed be an improvement. For the same reason, as "# amend!"
> will replace the message wholesale, it would also be a good idea for
> the first commit to be hidden like all the other commits that would
> not contribute to the text,
But the amend! commit does not target the first commit - it replaces the
message of the second commit so I think we should keep the first message
as shown below. You can see a different example with a squash! message
at [1]
> # This is the combination fo 4 commits
> # 1. Base subject
> # 2. Another subject
> # 3. fixup! Base subject
> # 4. amend! Another subject
Base subject
Base body
# -------------------------------------
> A better subject
>
> A better body.
Thanks
Phillip
[1]
https://lore.kernel.org/git/4b505228-4846-4a48-9255-e249f4e70a1f@gmail.com
^ permalink raw reply
* [PATCH] t9811: replace 'test -f' and '! test -f' with 'test_path_*'
From: Marcelo Machado Lage @ 2026-07-02 14:07 UTC (permalink / raw)
To: git; +Cc: Marcelo Machado Lage, Vinicius Lira de Freitas, Junio C Hamano
Replace the basic shell commands 'test -f', with more modern test
helpers 'test_path_is_file' and 'test_path_is_missing'.
Co-authored-by: Vinicius Lira de Freitas <vinilira@usp.br>
Signed-off-by: Vinicius Lira de Freitas <vinilira@usp.br>
Signed-off-by: Marcelo Machado Lage <marcelomlage@usp.br>
---
t/t9811-git-p4-label-import.sh | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/t/t9811-git-p4-label-import.sh b/t/t9811-git-p4-label-import.sh
index 7614dfbd95..93d6b4c479 100755
--- a/t/t9811-git-p4-label-import.sh
+++ b/t/t9811-git-p4-label-import.sh
@@ -62,9 +62,9 @@ test_expect_success 'basic p4 labels' '
cd main &&
git checkout TAG_F1_ONLY &&
- ! test -f f2 &&
+ test_path_is_missing f2 &&
git checkout TAG_WITH\$_SHELL_CHAR &&
- test -f f1 && test -f f2 && test -f file_with_\$metachar &&
+ test_path_is_file f1 && test_path_is_file f2 && test_path_is_file file_with_\$metachar &&
git show TAG_LONG_LABEL | grep -q "A Label second line"
)
@@ -102,11 +102,11 @@ test_expect_success 'two labels on the same changelist' '
git checkout TAG_F1_1 &&
ls &&
- test -f f1 &&
+ test_path_is_file f1 &&
git checkout TAG_F1_2 &&
ls &&
- test -f f1
+ test_path_is_file f1
)
'
@@ -135,9 +135,9 @@ test_expect_success 'export git tags to p4' '
p4 labels ... | grep LIGHTWEIGHT_TAG &&
p4 label -o GIT_TAG_1 | grep "tag created in git:xyzzy" &&
p4 sync ...@GIT_TAG_1 &&
- ! test -f main/f10 &&
+ test_path_is_missing main/f10 &&
p4 sync ...@GIT_TAG_2 &&
- test -f main/f10
+ test_path_is_file main/f10
)
'
@@ -168,9 +168,9 @@ test_expect_success 'export git tags to p4 with deletion' '
cd "$cli" &&
p4 sync ... &&
p4 sync ...@GIT_TAG_ON_DELETED &&
- test -f main/deleted_file &&
+ test_path_is_file main/deleted_file &&
p4 sync ...@GIT_TAG_AFTER_DELETION &&
- ! test -f main/deleted_file &&
+ test_path_is_missing main/deleted_file &&
echo "checking label contents" &&
p4 label -o GIT_TAG_ON_DELETED | grep "tag on deleted file"
)
base-commit: e9019fcafe0040228b8631c30f97ae1adb61bcdc
--
2.34.1
^ permalink raw reply related
* Re: [ANNOUNCE] Git v2.55.0
From: Weijie Yuan @ 2026-07-02 14:07 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Linux Kernel, git-packagers
In-Reply-To: <xmqqv7b1w9vr.fsf@gitster.g>
On Mon, Jun 29, 2026 at 10:10:16AM -0700, Junio C Hamano wrote:
> The latest feature release Git v2.55.0 is now available at the
> usual places. It is comprised of 505 non-merge commits since
> v2.54.0, contributed by 100 people, 33 of which are new faces [*].
>
> The tarballs are found at:
>
> https://www.kernel.org/pub/software/scm/git/
>
> The following public repositories all have a copy of the 'v2.55.0'
> tag and the 'master' branch that the tag points at:
>
> url = https://git.kernel.org/pub/scm/git/git
> url = https://kernel.googlesource.com/pub/scm/git/git
> url = git://repo.or.cz/alt-git.git
> url = https://github.com/gitster/git
>
> New contributors whose contributions weren't in v2.54.0 are as follows.
> Welcome to the Git development community!
>
> Abhinav Gupta, Aliwoto, Arijit Banerjee, Brandon Chinn, Claude
> Sonnet 4.6, David Lin, Dominik Loidolt, Ethan Dickson, Hugo
> Osvaldo Barrera, Ivan Baluta, Jean-Christophe Manciot, Jonas
> Rebmann, Kévin Leprêtre, Koutian Wu, Kristofer Karlsson,
> Kushal Das, lilydjwg, Luke Martin, Luna Schwalbe, Matheus
> Afonso Martins Moreira, Matteo Beniamino, Michael Grossfeld,
> Owen Stephens, Rob McDonald, Saagar Jha, Scott Bauersfeld,
> Scott L. Burson, Sebastien Tardif, Shardul Natu, Siddh Raman
> Pant, slonkazoid, Tamir Duberstein, and Weijie Yuan.
Looks like your script counted Claude Sonnet 4.6 as one of the 33 new
contributors. ;-)
Anyway, let´s celebrate Git v2.55.0!
Thanks,
Weijie Yuan
^ permalink raw reply
* Re: [PATCH v2 1/4] t1517: skip svn tests if svn is not installed2sy
From: brian m. carlson @ 2026-07-02 14:47 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Jeff King
In-Reply-To: <xmqqzf0al51j.fsf@gitster.g>
[-- Attachment #1: Type: text/plain, Size: 1187 bytes --]
On 2026-07-01 at 22:27:04, Junio C Hamano wrote:
> "brian m. carlson" <sandals@crustytoothpaste.net> writes:
>
> > +test_lazy_prereq SVN '
> > + test_have_prereq PERL && test -n "$NO_SVN_TESTS" && perl -w -e "
> > + use SVN::Core;
> > + use SVN::Repos;
> > + \$SVN::Core::VERSION gt '1.1.0' or exit(42);
> > + "
> > +'
>
> If "have_prereq PERL" is not satisfied, SVN is not satisfied.
Correct.
> If NO_SVN_TESTS is an empty string (or unset), "test -n" fails, and
> SVN is not satisfied. Questionable---am I misreading this part of
> the logic???
I think that's reversed, yes.
> The perl script would not barf only if use SVN::* succeed and then
> SVN::Core::VERSION is strictly better than '1.1.0'. If not, i.e.,
> libsvn-perl is not available, or its version is older, then we fail
> with exit(42), and SVN is not satisfied.
Correct. And yes, this came in from `t/lib-git-svn.sh`. I'll probably
just simplify this to omit the version check since it's very unlikely
that anybody is using SVN 1.0 any more and, as Peff pointed out, this
doesn't actually work using a string comparison.
--
brian m. carlson (they/them)
Toronto, Ontario, CA
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 325 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox