]> git.99rst.org Git - git.git/log
git.git
3 weeks agohash: make git_hash_discard() idempotent
Jeff King [Wed, 8 Jul 2026 03:52:57 +0000 (23:52 -0400)]
hash: make git_hash_discard() idempotent

You must always either finalize or discard a hash context to release any
resources, but you must call only one such function. This creates extra
work for some callers, since their cleanup code paths need to know
whether they got there via their happy path (and the finalization
happened) or due to an error (in which case they need to discard).

Let's add an "active" flag that turns a redundant discard into a noop.
That lets you safely do this:

    git_hash_init(&ctx, algo);
    ...
    if (some_error)
            goto out;
    ...
    git_hash_final(result, &ctx);

  out:
    git_hash_discard(&ctx);

This should avoid future errors, and will also let us simplify a few
existing callers (in future patches).

Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
3 weeks agohash: document function pointers and wrappers
Jeff King [Wed, 8 Jul 2026 03:52:55 +0000 (23:52 -0400)]
hash: document function pointers and wrappers

We want people to use the git_hash_*() wrappers rather than the bare
function pointers in the git_hash_algo struct. Let's document them
rather than the bare pointers, and warn people away from the pointers.
Coccinelle will eventually force the use of the wrappers, but it's
helpful to lead readers in the right direction from the start.

While we're here we can document a few other bits of wisdom I've turned
up while working in this area:

  - You have to initialize the destination of a git_hash_clone(). This
    is something we may eventually change for efficiency, but we should
    definitely document the requirement for now.

  - You must eventually finalize or discard a hash, since some backends
    may allocate resources during initialization.

Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
3 weeks agohash: convert remaining direct function calls
Jeff King [Wed, 8 Jul 2026 03:52:53 +0000 (23:52 -0400)]
hash: convert remaining direct function calls

The previous patch added a coccinelle rule to make sure callers always
use git_hash_init() rather than direct function pointers from the algo
struct.

Let's do the same for the rest of the git_hash_*() wrappers. I split
these out because they're a bit different: they implicitly use the algop
pointer in the git_hash_ctx. So when we convert:

  -algo->update_fn(&ctx, buf, len);
  +git_hash_update(&ctx, buf, len);

we drop the reference to algo entirely! But this is always going to be
the right thing. If "algo" does not match what is in ctx.algop, then
we'd already be invoking undefined behavior.

So in addition to making it possible to add more logic to the
git_hash_*() functions, we're avoiding the need to pass around the extra
algo pointer and make sure that it matches what's in "ctx".

The rest of the patch is the mechanical application of that coccinelle
patch, plus a minor cleanup in test-synthesize.c to drop a now-unused
function parameter (since we don't have to pass around the algo
separately anymore).

Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
3 weeks agohash: use git_hash_init() consistently
Jeff King [Wed, 8 Jul 2026 03:52:49 +0000 (23:52 -0400)]
hash: use git_hash_init() consistently

We'd like to add more logic to git_hash_init(), but many callers skip it
and call algop->init_fn() directly. Let's make sure we're consistently
using the wrapper by adding a coccinelle rule.

Besides the coccinelle file itself, this is a purely mechanical
conversion based on the patch it generates. There should be no bare
init_fn() calls left (except for the one in the wrapper).

Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
3 weeks agoMerge branch 'jk/hash-algo-leak-fixes' into jk/git-hash-cleanups
Junio C Hamano [Tue, 7 Jul 2026 17:52:48 +0000 (10:52 -0700)]
Merge branch 'jk/hash-algo-leak-fixes' into jk/git-hash-cleanups

* jk/hash-algo-leak-fixes:
  hash: add platform-specific discard functions
  hash: fix memory leak copying sha256 gcrypt handles
  http: discard hash in dumb-http http_object_request
  check_stream_oid(): discard hash on read error
  patch-id: discard hash when done
  csum-file: provide a function to release checkpoints
  csum-file: always finalize or discard hash
  hash: add discard primitive
  csum-file: drop discard_hashfile()

4 weeks agohash: add platform-specific discard functions
Jeff King [Thu, 2 Jul 2026 08:13:49 +0000 (04:13 -0400)]
hash: add platform-specific discard functions

Our git_hash_discard() is a bit hacky: it just calls git_hash_final()
into a dummy result buffer, using the side effect that each
implementation's Final() function will also free any resources.

This is probably not too terrible, since generating the final hash is
not that expensive and we'd mostly call discard on unusual or error code
paths. But we can do better by widening the platform API a bit to add an
explicit discard function.

This requires an annoying amount of boilerplate:

  - Each algorithm needs a git_$ALGO_discard() wrapper that dereferences
    the union'd git_hash_ctx into the type-safe field. So sha1 + sha256
    + sha1-unsafe, plus a BUG() for the unknown algo. And then these all
    need to be referenced in the git_hash_algo structs.

  - Platforms which don't do anything special to discard now need a
    fallback function which does nothing. And we need this for each algo
    (sha1, sha256, and sha1-unsafe).

  - Platforms which do need to discard must define their discard
    functions. This includes sha1/openssl, sha256/openssl, and
    sha256/gcrypt (no sha1-unsafe here as it sits atop the sha1/openssl
    functions).

  - Algo selection needs to point platform_*_Discard to the appropriate
    underlying macro, or indicate that the fallback should be used. We
    have a similar situation for the Clone function (where a straight
    memcpy() of the context struct is not enough for some platforms).
    I've tied Discard to the same flag used by Clone here, since they
    are basically the same problem: is the hash context a sequence of
    bytes, or does it need smart copying/discarding?

It's easy to miss a case here since we don't even compile the
implementations we aren't using. I've tested with each of:

  - no flags, which uses our internal sha1/sha256 implementations, both
    of which exercise the noop fallback function

  - OPENSSL_SHA1_UNSAFE=1, which checks that our unsafe macro
    redirections work

  - OPENSSL_SHA1=1, though you should not do that in real life!

  - OPENSSL_SHA256=1, passes tests with GIT_TEST_DEFAULT_HASH=sha256

  - GCRYPT_SHA256=1, which likewise passes

The other implementations do not set the CLONE_HELPER flag, so they
treat the context as bytes and should be fine with the fallback.

Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
4 weeks agohash: fix memory leak copying sha256 gcrypt handles
Jeff King [Thu, 2 Jul 2026 08:09:07 +0000 (04:09 -0400)]
hash: fix memory leak copying sha256 gcrypt handles

Our abstracted hash-algorithm API allows for cloning a hash context. By
default this just memcpy()s the bytes, but specific implementations can
provide a custom clone function.

Our API is based around the way that OpenSSL works, which is that you
first initialize the destination context, then copy into it. In our code
that is this:

  algo->init_fn(&dst);
  git_hash_clone(&dst, src);

and that translates into OpenSSL calls like:

  /* init_fn */
  dst->ectx = EVP_MD_CTX_new();
  EVP_DigestInit_ex(dst->ectx, EVP_sha256());
  /* clone */
  EVP_MD_CTX_copy_ex(dst->ectx, src->ectx);

So the allocation happens in the first step, and then the clone is just
copying values (the DigestInit is initializing values that just get
overwritten, but that's not wrong, just a little inefficient).

But libgcrypt doesn't work like that! Its copy function initializes dst
from scratch. So when using the sha256 gcrypt backend, that becomes:

  /* init_fn; this allocates */
  gcry_md_open(&dst, GCRY_MD_SHA256);
  /* clone; this also allocates, leaking the previous value! */
  gcry_md_copy(&dst, src);

You can see the leaks in the test suite by running:

  make \
    SANITIZE=leak \
    GCRYPT_SHA256=1 \
    GIT_TEST_DEFAULT_SHA=256 \
    test

which has many failures, as opposed to building with OPENSSL_SHA256,
which is leak-free.

The easy fix here is for the clone function to close the open context
we're about to overwrite. It's a little inefficient (we did a pointless
open in the init function), but probably not a big deal in practice.

If our API went the other way, assuming that we're always cloning into
garbage bytes, then we could be more efficient. We'd teach OpenSSL's
clone function to do its own new(), skip the DigestInit, and then copy
into it. And gcrypt could stick with just the copy() call.

But look again at the asymmetry in the very first code example. We call
the init function straight from the git_hash_algo struct, and then
subsequent calls are dispatched through our git_hash_* wrappers. If you
wanted to clone into an uninitialized destination, you'd do something
like:

  algo->clone_fn(&dst, src);

instead. That would require changing all of the callers. There's not
that many of them, but I don't know that it's worth changing our calling
conventions to try to reclaim this tiny bit of efficiency.

Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
4 weeks agohttp: discard hash in dumb-http http_object_request
Jeff King [Thu, 2 Jul 2026 08:07:07 +0000 (04:07 -0400)]
http: discard hash in dumb-http http_object_request

Usually an object request results in finish_http_object_request()
calling git_hash_final_oid(), after we've received all of the data. But
if we hit an error, we'll bail early and free the http_object_request,
dropping the git_hash_ctx entirely.  This can cause a leak for hash
implementations that allocate memory in their context, like OpenSSL >=
3.0.

The obvious fix is for abort_http_object_request() to call
git_hash_discard(), under the assumption that every request is either
finished or aborted. But that's not quite true:

  1. Not everybody calls the abort function. Sometimes they jump
     straight to release_http_object_request(). So we'd have to put it
     there.

  2. After the finish function finalizes the hash, we can still
     encounter errors! In that case we end up aborting or releasing,
     and they must not discard that hash (since that would be a
     double-free).

So we'll keep a flag marking the validity of the hash_ctx field of the
request. The lifetime is simple: it is valid immediately after creation,
up until we call finalize. And then our release function can just
conditionally discard the hash based on that flag.

This fixes test failures in t5550 and t5619 when run with:

  make SANITIZE=leak \
       OPENSSL_SHA256=1 \
       GIT_TEST_DEFAULT_HASH=sha256 \
       test

The flag handling could be removed if the hash-discard function were
idempotent. This could be done easily-ish by having the underlying
hash functions (like the ones in sha256/openssl.h) set the context
pointer to NULL after free-ing. But it's something that every platform
implementation would have to remember to do, and the benefit for the
callers is not that huge (it would let us shave a few lines here and
probably in a few other spots).

Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
4 weeks agocheck_stream_oid(): discard hash on read error
Jeff King [Thu, 2 Jul 2026 08:05:03 +0000 (04:05 -0400)]
check_stream_oid(): discard hash on read error

The happy path of check_stream_oid() is to initialize a hash, feed the
loose object zlib stream into it, and then get the final result. But if
we hit a zlib error or see extra cruft we'll bail early with an error.

Since we never call git_hash_final() in this cases, any resources held
by the git_hash_ctx may be leaked. Our default hash algorithms don't
allocate anything in the hash_ctx, but some implementations do. For
example, running:

  make SANITIZE=leak \
       OPENSSL_SHA256=1 \
       GIT_TEST_DEFAULT_HASH=sha256 \
       test

will fail t1450, since it feeds corrupted objects that cause us to bail
from check_stream_oid(). This patch fixes it by discarding the hash in
those early return paths. Trying to jump to a common "out:" label is not
worth it here, as we must _not_ discard a hash that was already fed to
git_hash_final(). And the hash_ctx itself does not carry any information
(so we cannot check for a NULL pointer, etc).

Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
4 weeks agopatch-id: discard hash when done
Jeff King [Thu, 2 Jul 2026 08:04:11 +0000 (04:04 -0400)]
patch-id: discard hash when done

When computing a patch-id, we have a flush_one_hunk() helper that calls
git_hash_final() on our running hunk git_hash_ctx, and then
reinitializes that context for the next hunk.

When we run out of hunks to look at, we return, discarding the
git_hash_ctx. This can cause a leak if the hash implementation we are
using allocates any memory during its initialization. This includes
OpenSSL >= 3.0, for both SHA-1 and SHA-256. Normally we would not use
SHA-1 here at all, as we only recommend using non-DC implementations for
the "unsafe" variant (and patch-id, though they probably _could_ use the
unsafe variant, were never taught to do so).

But it is certainly a problem for SHA-256, which you can see with:

  make SANITIZE=leak \
       OPENSSL_SHA256=1 \
       GIT_TEST_DEFAULT_HASH=sha256 \
       test

That results in leak failures of 60 scripts, 57 of which are fixed by
this patch (basically anything which runs rebase will hit this case).

Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
4 weeks agocsum-file: provide a function to release checkpoints
Jeff King [Thu, 2 Jul 2026 08:03:19 +0000 (04:03 -0400)]
csum-file: provide a function to release checkpoints

A hashfile_checkpoint struct is basically just a copy of the hash_ctx
state at a given point in the file. As such, it contains its own
git_hash_ctx which may (depending on the underlying hash implementation)
need to be discarded when we're done with it.

Let's add a "release" function which cleans up the hash context it
holds. I chose "release" here and not "discard" because you'd use this
to clean up every checkpoint, whether you used it or not. As opposed to
git_hash_discard(), which is needed only if you didn't call
git_hash_final().

There are only two callers which use hashfile_checkpoints, and we can
add release calls to both. When built with "SANITIZE=leak
OPENSSL_SHA1_UNSAFE=1", this makes both t1050 and t9300 leak-free.

Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
4 weeks agocsum-file: always finalize or discard hash
Jeff King [Thu, 2 Jul 2026 08:01:30 +0000 (04:01 -0400)]
csum-file: always finalize or discard hash

When a hashfile struct is created, we always initialize the git_hash_ctx
inside it. We usually end up in hashfile_finalize(), which passes that
ctx to git_hash_final(), cleaning it up.

But a few code paths don't do so:

  1. If we bail on the hashfile and call free_hashfile() directly rather
     than finalizing.

  2. If the skip_hash flag is set, the hashfile_finalize() call will
     never call git_hash_final(). (You might think that we should just
     avoid git_hash_init() entirely in this case, but the skip_hash flag
     is set by the caller after the hashfile is initialized).

For most hash implementations this is OK, but for ones that allocate on
initialization it causes a memory leak. You can see many failures by
running:

  make SANITIZE=leak OPENSSL_SHA1_UNSAFE=1 test

since OpenSSL >= 3.0 is such an allocating hash implementation (and
csum-file uses the "unsafe" algorithm variant).

We can solve this by calling git_hash_discard() as appropriate.

Note that free_hashfile() is used both directly by callers to abort
without finalizing, and by hashfile_finalize() to free memory. In the
latter case we _don't_ want to call git_hash_discard(), because we'll
already have either finalized or discarded it. So we'll push that to an
internal "free_memory" function, and keep free_hashfile() as the public
interface to abort a hashfile without finalizing.

This fix makes several scripts leak-free with the command above: t1600,
t1601, t2107, t7008, t9210, t9211.

Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
4 weeks agohash: add discard primitive
Jeff King [Thu, 2 Jul 2026 07:59:53 +0000 (03:59 -0400)]
hash: add discard primitive

The usual life-cycle for a git_hash_ctx is calling git_hash_init(),
adding some data, and then using git_hash_final() to get the output
digest and free any resources.

Sometimes we decide to abort the operation without the final() call
(e.g., due to errors or other reasons). In that case we just abandon the
hash_ctx completely and let it go out of scope. For most hash
implementations this is fine; they were just holding values directly in
the struct.

But some implementations do allocate memory, and in these cases we leak
the memory. Notably OpenSSL >= 3.0 requires us to allocate the digest
context on the heap with EVP_MD_CTX_new().

Let's provide a git_hash_discard() function that can be used in these
code paths to free any resources. For now we'll implement it by just
calling git_hash_final() into a dummy output, relying on its side effect
of freeing the resources. Our view of the underlying hash implementation
is abstracted behind the platform_SHA_* macros, so that's the best we
can do without widening that interface.

It's a little inefficient, but probably not noticeably so in practice,
especially as we'd usually hit this on an error code path. And by
abstracting it in this function, we can later swap it out when the
platform_SHA interface lets us do so.

Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
4 weeks agocsum-file: drop discard_hashfile()
Jeff King [Thu, 2 Jul 2026 07:57:44 +0000 (03:57 -0400)]
csum-file: drop discard_hashfile()

Commit c3d034df16 (csum-file: introduce discard_hashfile(), 2024-07-25)
added a cleanup function that no longer has any callers. In that commit
we adjusted do_write_index() to use the new function. But a similar fix
occurred on a parallel branch, making free_hashfile() public, and the
merge resolution in 1b6b2bfae5 (Merge branch 'ps/leakfixes-part-4',
2024-08-23) took the free_hashfile() version.

So now we have two functions, discard_hashfile() and free_hashfile(),
and we only need one. Which one do we want to keep?

The only difference between them is that the discard variant also closes
the descriptors held in the struct. Let's look at the three callers:

  1. In finalize_hashfile() we've either already closed the descriptors
     (if the CSUM_CLOSE flag is passed) or the caller didn't want them
     closed (if it didn't pass that flag). So we want the more limited
     free_hashfile().

  2. In object-file.c:flush_packfile_transaction() we close the
     descriptor ourselves. So discard_hashfile() could save us a line of
     code.

  3. In do_write_index() we don't close the descriptor. This was the spot
     for which c3d034df16 added the discard function in the first place,
     but I'm skeptical that closing the descriptor here is the right
     thing. It is true that we are done with the descriptor at this
     point and closing it would be ideal. But we don't really own it!

     The descriptor comes from a tempfile struct (as part of a lock) and
     that tempfile will hold on to the descriptor and try to close it
     when it is deleted. This might happen at the end of the program, in
     which case the double-close is mostly harmless (we might
     accidentally close some other open descriptor, but at that point
     we're just closing and unlinking everything we can).

     But in theory it could also cause subtle bugs. If do_write_index()
     fails, we return the error up the stack and would eventually end up
     in write_locked_index(). There we roll back the lock file on error,
     which will close the descriptor. So now we get our double close,
     and we might actually close something else that was opened in the
     interim.

     This is probably unlikely in practice (as soon as we see the error
     we'd mostly be unwinding the stack, not opening new files). But it
     highlights a potential problem with the discard_hashfile()
     interface: the hashfile doesn't necessarily own that descriptor.

Note that I said "descriptors" plural above. Those callers all care
about the "fd" member of the struct. But discard_hashfile() also closes
check_fd. That is only used if the struct is initialized with
hashfd_check(), and neither of its two callers call either discard or
free (they always "finalize" instead). So closing it is irrelevant for
the current callers.

I think we're better off sticking with the simpler free_hashfile()
interface, and the handful of callers can decide how to handle the
descriptors themselves.

Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
5 weeks agoGit 2.55 v2.55.0
Junio C Hamano [Mon, 29 Jun 2026 14:58:39 +0000 (07:58 -0700)]
Git 2.55

Signed-off-by: Junio C Hamano <redacted>
5 weeks agoMerge branch 'jk/t5551-expensive-test-timeouts-fix'
Junio C Hamano [Mon, 29 Jun 2026 14:56:22 +0000 (07:56 -0700)]
Merge branch 'jk/t5551-expensive-test-timeouts-fix'

The Apache timeout in HTTP tests has been increased to prevent test
failures on heavily loaded CI runners. The tests creating an
enormous number of refs have been isolated to their own repositories
to avoid slowing down subsequent tests.

* jk/t5551-expensive-test-timeouts-fix:
  t5551: put many-tags case into its own repo
  t/lib-httpd: bump apache timeout

5 weeks agot5551: put many-tags case into its own repo
Jeff King [Sun, 28 Jun 2026 08:03:45 +0000 (04:03 -0400)]
t5551: put many-tags case into its own repo

Most of the t5551 http fetch tests use a handful of refs. But there are
a few test cases which check our handling of large numbers of refs.
These tests use the same server-side repo, so all subsequent tests end
up having to consider those extra refs, too.

The result is that the test script is a bit slower than it needs to be.
In a normal run, moving the "2,000 tags" test into its own repo drops my
runtime for the whole script from ~2.7s to ~1.9s.

This is a modest gain, but when we add the "--long" flag it gets much
bigger. There we trigger a test (marked with EXPENSIVE) that adds
100,000 tags, and the script runtime jumps to ~95s. But if we use the
same "many tags" repo for that, our runtime drops to just ~37s.

This is a pretty easy win to drop the cost of the script. It may even be
a larger gain on a heavily loaded system, since one of the main costs
here is unpacked refs, which are heavy on system time and I/O costs.

It's possible we are reducing test coverage, since all of those other
tests were inadvertently using large ref advertisements (and thus could
have uncovered some unexpected interaction). But that seems somewhat
unlikely; the tests targeted at the large number of refs are doing
roughly similar things to the other tests.

Note that the real performance culprit is the 100k-tag --long test, not
the 2k-tag one. So we could just let the 100k one use its own repo, and
keep the 2k tags in the main repo. But since these two tests are
somewhat interlinked, it's easier to just move them both (and it does
provide a small gain even for the 2000-tag test). I also notice that the
2000-tag test is gated on the CMDLINE_LIMIT prereq, and without that the
later EXPENSIVE test will fail (since we won't have a too-many-refs
clone). Nobody seems to have noticed or complained after many years, and
I left it alone for this patch.

Signed-off-by: Jeff King <redacted>
[jc: made the new "many-tags.git" bare to match the original "repo.git"]
Signed-off-by: Junio C Hamano <redacted>
5 weeks agoMerge branch 'js/http-https-proxy-fix'
Junio C Hamano [Sun, 28 Jun 2026 22:18:24 +0000 (15:18 -0700)]
Merge branch 'js/http-https-proxy-fix'

We lost ability to use https:// proxies during this cycle; this is
a hotfix for the regression.

* js/http-https-proxy-fix:
  http: accept https:// proxies again

5 weeks agot/lib-httpd: bump apache timeout
Jeff King [Sun, 28 Jun 2026 08:00:09 +0000 (04:00 -0400)]
t/lib-httpd: bump apache timeout

Since enabling more tests with 7a094d68a2 (ci: run expensive tests on
push builds to integration branches, 2026-05-08), we sometimes see test
failures or timeouts in GitHub CI. The culprit seems to be the "enormous
ref negotiation" test in t5551, which creates ~100k tag refs in our http
server-side repo.

Iterating through the loose refs of this repo to generate a ref
advertisement can take a long time, especially on a platform with slow
I/O. On my otherwise unloaded local machine, a cold cache ref
advertisement takes ~10s. On a busy CI machine running tests in
parallel, it can presumably top 60s, which runs afoul of Apache's
default CGI timeout.

The result in t5551 is a test failure, where Apache simply hangs up the
connection and the client reports an error. But worse, t5559 runs the
same test with HTTP/2, and a bug in Apache causes the connection to hang
indefinitely! We eventually see this as a CI timeout after 6 hours.

Let's bump Apache's timeout to something much larger: 600 seconds. This
doesn't eliminate the possibility of a timeout, but it makes it much
less likely. It should eliminate both the test failures and the CI
timeouts in practice, and it protects us from running into similar
problems with other tests in the future.

There are two counter-arguments to consider.

One, could/should we just make the test faster? Probably yes. The
biggest mistake here is having such an absurd number of unpacked refs on
a system which is bottle-necked on I/O. But I think it's worth bumping
the timeout so that we can fix this (and possibly other) correctness
issues, and then consider performance separately (which we'll do in
subsequent patches).

And two, is this just papering over a problem that users might see in
the real world? We could teach Git to handle this case more gracefully
with optimizations or keep-alives. But I think it's really an artificial
situation. You need a combination of this silly number of loose refs,
plus a very heavily loaded system. If you were trying to run a real
server and it took more than 60s to generate the ref advertisement, I
don't think the timeout is your biggest problem. Your crappy service is,
and you should adjust your resources to match your load. I.e., it is
probably reasonable for Git to assume that advertisements happen
fast-ish and don't need protocol-level keepalives.

Though the patch here is small, tons of work went into analyzing the
problem. Many thanks to the contributors credited below.

Helped-by: Michael Montalbo <redacted>
Helped-by: Patrick Steinhardt <redacted>
Signed-off-by: Jeff King <redacted>
Signed-off-by: Junio C Hamano <redacted>
5 weeks agohttp: accept https:// proxies again
Johannes Schindelin [Sat, 27 Jun 2026 17:17:56 +0000 (17:17 +0000)]
http: accept https:// proxies again

Since 663d7abe07ea (http: reject unsupported proxy URL schemes,
2026-05-05), set_curl_proxy_type() returns 0 only for the "http"
and SOCKS variants via dedicated early returns, and -1 for
everything else. The "https" branch configures the CURL handle for
HTTPS proxying but then falls through to the trailing `return -1`
intended for unknown schemes, so the caller in get_curl_handle()
treats a perfectly valid https:// proxy URL as unsupported and
refuses to use it.

Noticed while looking into a Coverity report against the same
function; the unchecked curl_easy_setopt() return values it flags
are orthogonal to this fix.

Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <redacted>
Signed-off-by: Junio C Hamano <redacted>
5 weeks agoMerge tag 'l10n-2.55.0-v1' of https://github.com/git-l10n/git-po
Junio C Hamano [Sun, 28 Jun 2026 15:28:08 +0000 (08:28 -0700)]
Merge tag 'l10n-2.55.0-v1' of https://github.com/git-l10n/git-po

l10n-2.55.0-v1

* tag 'l10n-2.55.0-v1' of https://github.com/git-l10n/git-po:
  l10n: zh-TW.po: Update Chinese (Traditional) translation
  l10n: uk: add 2.55 translation
  l10n: ga.po: update for Git 2.55
  l10n: fr: mass fix of typos
  l10n: fr: version 2.55
  l10n: po-id for 2.55
  l10n: AGENTS.md: add quotation mark preservation guidelines
  l10n: zh_CN: updated translation for 2.55
  l10n: TEAMS: change Simplified Chinese team leader
  l10n: sv.po: Update Swedish translation
  l10n: ca.po: update Catalan translation
  l10n: tr: Update Turkish translations
  l10n: bg.po: Updated Bulgarian translation (6322t)
  l10n: it: fix italian usage messages alignment

5 weeks agoMerge branch '2.55-uk-pr' of github.com:arkid15r/git-ukrainian-l10n
Jiang Xin [Sun, 28 Jun 2026 11:25:08 +0000 (19:25 +0800)]
Merge branch '2.55-uk-pr' of github.com:arkid15r/git-ukrainian-l10n

* '2.55-uk-pr' of github.com:arkid15r/git-ukrainian-l10n:
  l10n: uk: add 2.55 translation

5 weeks agoMerge branch 'l10n-ga-2.55' of github.com:aindriu80/git-po
Jiang Xin [Sun, 28 Jun 2026 08:49:15 +0000 (16:49 +0800)]
Merge branch 'l10n-ga-2.55' of github.com:aindriu80/git-po

* 'l10n-ga-2.55' of github.com:aindriu80/git-po:
  l10n: ga.po: update for Git 2.55

5 weeks agoMerge branch 'l10n/zh-TW/2026-06-26' of github.com:l10n-tw/git-po
Jiang Xin [Sun, 28 Jun 2026 08:20:41 +0000 (16:20 +0800)]
Merge branch 'l10n/zh-TW/2026-06-26' of github.com:l10n-tw/git-po

* 'l10n/zh-TW/2026-06-26' of github.com:l10n-tw/git-po:
  l10n: zh-TW.po: Update Chinese (Traditional) translation

5 weeks agoMerge branch 'ca-20260624-b' of github.com:Softcatala/git-po
Jiang Xin [Sun, 28 Jun 2026 08:17:45 +0000 (16:17 +0800)]
Merge branch 'ca-20260624-b' of github.com:Softcatala/git-po

* 'ca-20260624-b' of github.com:Softcatala/git-po:
  l10n: ca.po: update Catalan translation

5 weeks agoMerge branch 'zh_CN-2.55' of github.com:lilydjwg/git-po
Jiang Xin [Sun, 28 Jun 2026 08:15:39 +0000 (16:15 +0800)]
Merge branch 'zh_CN-2.55' of github.com:lilydjwg/git-po

* 'zh_CN-2.55' of github.com:lilydjwg/git-po:
  l10n: zh_CN: updated translation for 2.55
  l10n: TEAMS: change Simplified Chinese team leader

5 weeks agoMerge branch 'tr-l10n' of github.com:bitigchi/git-po
Jiang Xin [Sun, 28 Jun 2026 08:14:13 +0000 (16:14 +0800)]
Merge branch 'tr-l10n' of github.com:bitigchi/git-po

* 'tr-l10n' of github.com:bitigchi/git-po:
  l10n: tr: Update Turkish translations

5 weeks agoMerge branch 'po-id' of github.com:bagasme/git-po
Jiang Xin [Sun, 28 Jun 2026 08:12:30 +0000 (16:12 +0800)]
Merge branch 'po-id' of github.com:bagasme/git-po

* 'po-id' of github.com:bagasme/git-po:
  l10n: po-id for 2.55

5 weeks agoMerge branch 'master' of github.com:alshopov/git-po
Jiang Xin [Sun, 28 Jun 2026 08:11:24 +0000 (16:11 +0800)]
Merge branch 'master' of github.com:alshopov/git-po

* 'master' of github.com:alshopov/git-po:
  l10n: bg.po: Updated Bulgarian translation (6322t)

5 weeks agoMerge branch 'fr_v2.55' of github.com:jnavila/git
Jiang Xin [Sun, 28 Jun 2026 08:09:26 +0000 (16:09 +0800)]
Merge branch 'fr_v2.55' of github.com:jnavila/git

* 'fr_v2.55' of github.com:jnavila/git:
  l10n: fr: mass fix of typos
  l10n: fr: version 2.55

5 weeks agoMerge branch 'master' of github.com:nafmo/git-l10n-sv
Jiang Xin [Sun, 28 Jun 2026 08:07:00 +0000 (16:07 +0800)]
Merge branch 'master' of github.com:nafmo/git-l10n-sv

* 'master' of github.com:nafmo/git-l10n-sv:
  l10n: sv.po: Update Swedish translation

5 weeks agol10n: zh-TW.po: Update Chinese (Traditional) translation
Lumynous [Sat, 20 Jun 2026 11:36:09 +0000 (19:36 +0800)]
l10n: zh-TW.po: Update Chinese (Traditional) translation

Signed-off-by: Yi-Jyun Pan <redacted>
5 weeks agol10n: uk: add 2.55 translation
Arkadii Yakovets [Sat, 27 Jun 2026 18:42:28 +0000 (11:42 -0700)]
l10n: uk: add 2.55 translation

Co-authored-by: Kate Golovanova <redacted>
Signed-off-by: Arkadii Yakovets <redacted>
Signed-off-by: Kate Golovanova <redacted>
5 weeks agol10n: ga.po: update for Git 2.55
Aindriú Mac Giolla Eoin [Sat, 27 Jun 2026 13:41:58 +0000 (14:41 +0100)]
l10n: ga.po: update for Git 2.55

Signed-off-by: Aindriú Mac Giolla Eoin <redacted>
5 weeks agol10n: fr: mass fix of typos
Jean-Noël Avila [Wed, 24 Jun 2026 10:20:45 +0000 (12:20 +0200)]
l10n: fr: mass fix of typos

Helped-by: Kévin Leprêtre <redacted>
Signed-off-by: Jean-Noël Avila <redacted>
5 weeks agol10n: fr: version 2.55
Jean-Noël Avila [Sun, 14 Jun 2026 06:18:10 +0000 (08:18 +0200)]
l10n: fr: version 2.55

Signed-off-by: Jean-Noël Avila <redacted>
5 weeks agol10n: po-id for 2.55
Bagas Sanjaya [Sat, 27 Jun 2026 04:00:14 +0000 (11:00 +0700)]
l10n: po-id for 2.55

Update following components:

  * add-patch.c
  * apply.c
  * bisect.c
  * builtin/add.c
  * builtin/backfill.c
  * builtin/bisect.c
  * builtin/cat-file.c
  * builtin/checkout.c
  * builtin/config.c
  * builtin/fast-import.c
  * builtin/fetch.c
  * builtin/fsmonitor--daemon.c
  * builtin/hook.c
  * builtin/index-pack.c
  * builtin/interpret-trailers.c
  * builtin/last-modified.c
  * builtin/log.c
  * builtin/multi-pack-index.c
  * builtin/name-rev.c
  * builtin/pack-objects.c
  * builtin/push.c
  * builtin/repack.c
  * builtin/replay.c
  * builtin/repo.c
  * builtin/show-index.c
  * builtin/stash.c
  * builtin/submodule--helper.c
  * builtin/worktree.c
  * command-list.h
  * diff.c
  * fetch-pack.c
  * hook.c
  * list-objects-filter-options.c
  * lockfile.c
  * midx-write.c
  * midx.c
  * object-file.c
  * object.c
  * packfile.c
  * path-walk.c
  * pretty.c
  * promisor-remote.c
  * pseudo-merge.c
  * read-cache.c
  * refs.c
  * remote-curl.c
  * repack-midx.c
  * replay.c
  * repository.c
  * revision.c
  * sequencer.c
  * setup.c
  * submodule.c
  * t/helper/test-path-walk.c
  * t/helper/test-read-midx.c
  * trailer.c
  * git-send-email.perl

Translate following new components:

  * builtin/history.c
  * builtin/url-parse.c
  * compat/fsmonitor/fsm-listen-linux.c
  * sideband.c
  * t/helper/test-synthesize.c

Signed-off-by: Bagas Sanjaya <redacted>
5 weeks agoMerge branch 'master' of github.com:mbeniamino/git-po
Jiang Xin [Fri, 26 Jun 2026 12:51:39 +0000 (20:51 +0800)]
Merge branch 'master' of github.com:mbeniamino/git-po

* 'master' of github.com:mbeniamino/git-po:
  l10n: it: fix italian usage messages alignment

5 weeks agol10n: AGENTS.md: add quotation mark preservation guidelines
Jiang Xin [Fri, 26 Jun 2026 11:57:52 +0000 (19:57 +0800)]
l10n: AGENTS.md: add quotation mark preservation guidelines

Add a "Preserving Quotation Marks" section to prevent AI-assisted
translation and review from incorrectly converting language-specific
UTF-8 curly quotes (e.g., â€ž U+201E, " U+201C for Bulgarian) into
ASCII straight quotes " (U+0022), which would cause PO string
truncation and syntax errors.

Also update the "Special characters" item in the Quality checklist
to reference the new section.

Signed-off-by: Jiang Xin <redacted>
5 weeks agol10n: zh_CN: updated translation for 2.55
lilydjwg [Sun, 21 Jun 2026 08:16:11 +0000 (16:16 +0800)]
l10n: zh_CN: updated translation for 2.55

Reviewed-by: Jiang Xin <redacted>
Reviewed-by: Fangyi Zhou <redacted>
Signed-off-by: lilydjwg <redacted>
5 weeks agol10n: TEAMS: change Simplified Chinese team leader
lilydjwg [Mon, 22 Jun 2026 06:20:21 +0000 (14:20 +0800)]
l10n: TEAMS: change Simplified Chinese team leader

Signed-off-by: lilydjwg <redacted>
5 weeks agoMerge branch 'ps/t4216-tap-fix'
Junio C Hamano [Fri, 26 Jun 2026 02:49:01 +0000 (19:49 -0700)]
Merge branch 'ps/t4216-tap-fix'

TAP output breakage fix.

* ps/t4216-tap-fix:
  t4216: fix no-op test that breaks TAP output

5 weeks agot4216: fix no-op test that breaks TAP output
Patrick Steinhardt [Fri, 19 Jun 2026 07:20:20 +0000 (09:20 +0200)]
t4216: fix no-op test that breaks TAP output

In t4216 we have have a prerequisite that is active in case the system's
`char` type is signed by default. This prerequisite isn't really used by
anything though: while it is used to guard one of our tests, that
specific test is essentially a no-op. So all this infrastructure does is
to provide some debugging hint to a reader that pays a lot of attention.

Besides that, the way we set up the prerequisite also results in broken
TAP output on systems where `char` is unsigned by default: we use
`test_cmp()` to diff two files outside of of any test body, and if the
files differ we enable the prerequisite. If so, the call to `test_cmp()`
would also print output, and that output is of course not valid TAP
output.

That wasn't a problem before 389c83025d (t: let prove fail when parsing
invalid TAP output, 2026-06-04), because our TAP parser was configured
to be lenient. But starting with that commit, t4216 is now failing on
systems with unsigned chars.

Drop the whole infrastructure. The prerequisite is not used anywhere
else, and the only location where it's used doesn't really provide much
value.

Reported-by: Todd Zullinger <redacted>
Signed-off-by: Patrick Steinhardt <redacted>
Tested-by: Todd Zullinger <redacted>
Signed-off-by: Junio C Hamano <redacted>
5 weeks agol10n: sv.po: Update Swedish translation
Peter Krefting [Thu, 25 Jun 2026 15:16:10 +0000 (16:16 +0100)]
l10n: sv.po: Update Swedish translation

Reviewed-by: Tuomas Ahola <redacted>
Signed-off-by: Peter Krefting <redacted>
5 weeks agol10n: ca.po: update Catalan translation
Mikel Forcada [Thu, 25 Jun 2026 08:14:24 +0000 (10:14 +0200)]
l10n: ca.po: update Catalan translation

Signed-off-by: Mikel Forcada <redacted>
5 weeks agol10n: tr: Update Turkish translations
Emir SARI [Tue, 16 Jun 2026 17:41:01 +0000 (20:41 +0300)]
l10n: tr: Update Turkish translations

Signed-off-by: Emir SARI <redacted>
5 weeks agol10n: bg.po: Updated Bulgarian translation (6322t)
Alexander Shopov [Sun, 14 Jun 2026 11:27:13 +0000 (13:27 +0200)]
l10n: bg.po: Updated Bulgarian translation (6322t)

Signed-off-by: Alexander Shopov <redacted>
5 weeks agoGit 2.55-rc2 v2.55.0-rc2
Junio C Hamano [Tue, 23 Jun 2026 03:04:38 +0000 (20:04 -0700)]
Git 2.55-rc2

Signed-off-by: Junio C Hamano <redacted>
5 weeks agoMerge branch 'hn/macos-linker-warning'
Junio C Hamano [Tue, 23 Jun 2026 03:05:04 +0000 (20:05 -0700)]
Merge branch 'hn/macos-linker-warning'

Xcode 15 and later has a linker set to complain when the same library
archive is listed twice on the command line.  Squelch the annoyance.

* hn/macos-linker-warning:
  config.mak.uname: avoid macOS dup-library warning

5 weeks agoMerge branch 'js/win32-localtime-r'
Junio C Hamano [Tue, 23 Jun 2026 03:05:03 +0000 (20:05 -0700)]
Merge branch 'js/win32-localtime-r'

Build-fix for 32-bit Windows.

* js/win32-localtime-r:
  win32: ensure that `localtime_r()` is declared even in i686 builds

5 weeks agoMerge branch 'ps/gitlab-ci-windows'
Junio C Hamano [Tue, 23 Jun 2026 03:05:03 +0000 (20:05 -0700)]
Merge branch 'ps/gitlab-ci-windows'

Wean the Windows builds in GitLab CI procedure away from
(unfortunately unreliable) Chocolatey to install dependencies.

* ps/gitlab-ci-windows:
  gitlab-ci: migrate Windows builds away from Chocolatey

6 weeks agowin32: ensure that `localtime_r()` is declared even in i686 builds
Johannes Schindelin [Mon, 22 Jun 2026 08:44:06 +0000 (08:44 +0000)]
win32: ensure that `localtime_r()` is declared even in i686 builds

The `__MINGW64__` constant is defined, surprise, surprise, only when
building for a 64-bit CPU architecture.

Therefore using it as a guard to define `_POSIX_C_SOURCE` (so that
`localtime_r()` is declared, among other functions) is not enough, we
also need to check `__MINGW32__`.

Technically, the latter constant is defined even for 64-bit builds. But
let's make things a bit easier to understand by testing for both
constants.

Making it so fixes this compile warning (turned error in GCC v14.1):

  archive-zip.c: In function 'dos_time':
  archive-zip.c:612:9: error: implicit declaration of function 'localtime_r';
  did you mean 'localtime_s'? [-Wimplicit-function-declaration]
    612 |         localtime_r(&time, &tm);
        |         ^~~~~~~~~~~
        |         localtime_s

Signed-off-by: Johannes Schindelin <redacted>
Signed-off-by: Junio C Hamano <redacted>
6 weeks agoA few more topics before -rc2
Junio C Hamano [Sun, 21 Jun 2026 23:41:10 +0000 (16:41 -0700)]
A few more topics before -rc2

Signed-off-by: Junio C Hamano <redacted>
6 weeks agoMerge branch 'js/objects-larger-than-4gb-on-windows-more'
Junio C Hamano [Sun, 21 Jun 2026 23:41:37 +0000 (16:41 -0700)]
Merge branch 'js/objects-larger-than-4gb-on-windows-more'

* js/objects-larger-than-4gb-on-windows-more:
  odb: use size_t for object_info.sizep and the size APIs
  packfile,delta: drop the `cast_size_t_to_ulong()` wrappers
  pack-objects: use size_t for in-core object sizes
  packfile: widen unpack_entry()'s size out-parameter to size_t
  pack-objects(check_pack_inflate()): use size_t instead of unsigned long
  patch-delta: use size_t for sizes
  compat/msvc: use _chsize_s for ftruncate

6 weeks agoMerge branch 'kw/gitattributes-typofix'
Junio C Hamano [Sun, 21 Jun 2026 23:41:37 +0000 (16:41 -0700)]
Merge branch 'kw/gitattributes-typofix'

* kw/gitattributes-typofix:
  gitattributes: fix eol attribute for Perl scripts

6 weeks agoconfig.mak.uname: avoid macOS dup-library warning
Harald Nordgren [Fri, 19 Jun 2026 20:32:07 +0000 (20:32 +0000)]
config.mak.uname: avoid macOS dup-library warning

Building on macOS with Xcode 15 or newer emits:

    ld: warning: ignoring duplicate libraries: 'libgit.a',
    'target/release/libgitcore.a'

Some link recipes list the same archive twice, which is harmless.
Quiet the warning instead.

Pass -Wl,-no_warn_duplicate_libraries on Xcode 15 and newer, whose
linkers added both the warning and the suppression flag (ld64-907
and dyld-1009). Earlier linkers reject the flag, so gate on the
linker version. Broaden the existing -fno-common version probe to
also match the "ld64-NNN" and "dyld-NNN" forms Xcode 15 reports.

Signed-off-by: Harald Nordgren <redacted>
Signed-off-by: Junio C Hamano <redacted>
6 weeks agoMerge branch 'js/objects-larger-than-4gb-on-windows'
Junio C Hamano [Fri, 19 Jun 2026 16:48:57 +0000 (09:48 -0700)]
Merge branch 'js/objects-larger-than-4gb-on-windows'

A hotfix to an earlier attempt to update code paths that assumed
"unsigned long" was long enough for "size_t".

* js/objects-larger-than-4gb-on-windows:
  zlib: properly clamp to uLong

6 weeks agozlib: properly clamp to uLong
Johannes Schindelin [Thu, 18 Jun 2026 13:50:18 +0000 (13:50 +0000)]
zlib: properly clamp to uLong

On platforms where `unsigned long` and `size_t` differ in bit size, we
want to clamp the buffers we pass to zlib to the former's size, as per
d05d666977 (git-zlib: handle data streams larger than 4GB, 2026-05-08).

The logic introduced in that commit performs a clamping to the bits,
though, which fails to do what is needed here: If too many bytes are
available in the buffers, we need to clamp to the maximum value of an
`unsigned long`. Otherwise, we ask zlib to use too small buffers, in the
worst case using 0 as the size (think: a value whose 32 lowest bits are
all zero).

Signed-off-by: Johannes Schindelin <redacted>
Signed-off-by: Junio C Hamano <redacted>
6 weeks agogitlab-ci: migrate Windows builds away from Chocolatey
Patrick Steinhardt [Mon, 15 Jun 2026 12:21:40 +0000 (14:21 +0200)]
gitlab-ci: migrate Windows builds away from Chocolatey

The Windows builds in GitLab CI use Chocolatey to install dependencies.
Unfortunately, Chocolatey seems to be very unreliable, which causes the
jobs to fail very regularly. This is a limitation that seems to be
somewhat known [1]:

  As an organization, you want 100% reliability (or at least that
  potential), and you may want full trust and control as well. This is
  something you can get with internally hosted packages, and you are
  unlikely to achieve from use of the Community Package Repository.

So using the Community Package Repository is kind of discouraged in case
one wants reliability. We _do_ want reliability though, and we cannot
easily switch to an enterprise license to fix this issue.

Introduce a new script that downloads and installs dependencies
directly. This has a couple of benefits:

  - We can drop our dependency on Chocolatey completely, thus improving
    reliability.

  - We can easily cache the installers.

  - We get direct control over the exact versions we install.

  - Installing dependencies is sped up from roundabout 3 minutes to 1
    minute.

[1]: https://docs.chocolatey.org/en-us/community-repository/community-packages-disclaimer/#summary

Signed-off-by: Patrick Steinhardt <redacted>
Signed-off-by: Junio C Hamano <redacted>
6 weeks agoHopefully final batch before -rc2
Junio C Hamano [Wed, 17 Jun 2026 18:09:50 +0000 (11:09 -0700)]
Hopefully final batch before -rc2

Signed-off-by: Junio C Hamano <redacted>
6 weeks agoMerge branch 'en/commit-graph-timestamp-fix'
Junio C Hamano [Wed, 17 Jun 2026 18:10:12 +0000 (11:10 -0700)]
Merge branch 'en/commit-graph-timestamp-fix'

compute_reachable_generation_numbers() in commit-graph used a 32-bit
integer to accumulate parent generations, which is OK for generation
number v1 (topological levels), but with generation number v2
(adjusted committer timestamps), it truncated timestamps beyond
2106.  Fixed by widening the accumulator to timestamp_t.

* en/commit-graph-timestamp-fix:
  commit-graph: use timestamp_t for max parent generation accumulator

6 weeks agoMerge branch 'dl/posix-unused-warning-clang'
Junio C Hamano [Wed, 17 Jun 2026 18:10:12 +0000 (11:10 -0700)]
Merge branch 'dl/posix-unused-warning-clang'

The UNUSED macro in 'compat/posix.h' has been updated to use a
newly introduced GIT_CLANG_PREREQ macro for compiler version
checks, and the existing GIT_GNUC_PREREQ macro has been modernized
to use explicit major/minor comparisons rather than bit-shifting.

* dl/posix-unused-warning-clang:
  compat/posix.h: simplify GIT_GNUC_PREREQ() comparison
  compat/posix.h: clean up GIT_GNUC_PREREQ() and UNUSED
  compat/posix.h: enable UNUSED warning messages for Clang

6 weeks agoMerge branch 'td/ls-files-pathspec-prefilter'
Junio C Hamano [Wed, 17 Jun 2026 18:10:11 +0000 (11:10 -0700)]
Merge branch 'td/ls-files-pathspec-prefilter'

`git ls-files --modified` and `git ls-files --deleted` have been
optimized to filter with pathspec before calling lstat() when there is
only a single pathspec item, avoiding unnecessary filesystem access
for entries that will not be shown.

* td/ls-files-pathspec-prefilter:
  ls-files: filter pathspec before lstat

6 weeks agoMerge branch 'ta/doc-config-adoc-fixes'
Junio C Hamano [Wed, 17 Jun 2026 18:10:11 +0000 (11:10 -0700)]
Merge branch 'ta/doc-config-adoc-fixes'

Various AsciiDoc markup fixes in 'git config' documentation and
related files to ensure lists and formatting are rendered correctly.

* ta/doc-config-adoc-fixes:
  doc: git-config: escape erroneous highlight markup
  doc: config/sideband: fix description list delimiter
  doc: config: terminate runaway lists

6 weeks agoMerge branch 'jc/t1400-fifo-cleanup'
Junio C Hamano [Wed, 17 Jun 2026 18:10:11 +0000 (11:10 -0700)]
Merge branch 'jc/t1400-fifo-cleanup'

Test cleanup.

* jc/t1400-fifo-cleanup:
  t1400: have fifo test clean after itself

6 weeks agoMerge branch 'td/describe-tag-iteration'
Junio C Hamano [Wed, 17 Jun 2026 18:10:11 +0000 (11:10 -0700)]
Merge branch 'td/describe-tag-iteration'

'git describe' has been taught to pass the 'refs/tags/' prefix down to
the ref iterator when '--all' is not requested, avoiding unnecessary
iteration over non-tag refs.

* td/describe-tag-iteration:
  describe: limit default ref iteration to tags

6 weeks agoMerge branch 'ps/transport-helper-tsan-fix'
Junio C Hamano [Wed, 17 Jun 2026 18:10:11 +0000 (11:10 -0700)]
Merge branch 'ps/transport-helper-tsan-fix'

The TSAN race in transfer_debug() within transport-helper.c has been
resolved by initializing the debug flag early in
bidirectional_transfer_loop() before spawning worker threads, allowing
the removal of a TSAN suppression.

* ps/transport-helper-tsan-fix:
  transport-helper: fix TSAN race in transfer_debug()

6 weeks agoGit 2.55-rc1 v2.55.0-rc1
Junio C Hamano [Wed, 17 Jun 2026 12:38:52 +0000 (05:38 -0700)]
Git 2.55-rc1

Signed-off-by: Junio C Hamano <redacted>
6 weeks agoMerge branch 'ab/index-pack-retain-child-bases'
Junio C Hamano [Wed, 17 Jun 2026 12:39:13 +0000 (05:39 -0700)]
Merge branch 'ab/index-pack-retain-child-bases'

"git index-pack" has been optimized by retaining child bases in the
delta cache instead of immediately freeing them, letting the existing
cache limit policy decide eviction.

* ab/index-pack-retain-child-bases:
  index-pack: retain child bases in delta cache

6 weeks agoMerge branch 'js/osxkeychain-build-wo-rust'
Junio C Hamano [Wed, 17 Jun 2026 12:39:13 +0000 (05:39 -0700)]
Merge branch 'js/osxkeychain-build-wo-rust'

Build fix.

* js/osxkeychain-build-wo-rust:
  osxkeychain: fix build with Rust

6 weeks agoosxkeychain: fix build with Rust
Johannes Schindelin [Wed, 17 Jun 2026 10:11:13 +0000 (10:11 +0000)]
osxkeychain: fix build with Rust

Without NO_RUST defined, the varint encoder/decoder lives in the
RUST_LIB, which needs to be linked. Symptom:

cc [... -o contrib/credential/osxkeychain/git-credential-osxkeychain [...]
Undefined symbols for architecture x86_64:
  "_decode_varint", referenced from:
      _read_untracked_extension in libgit.a[x86_64][63](dir.o)
      _read_untracked_extension in libgit.a[x86_64][63](dir.o)
      _read_one_dir in libgit.a[x86_64][63](dir.o)
      _read_one_dir in libgit.a[x86_64][63](dir.o)
      _load_cache_entry_block in libgit.a[x86_64][174](read-cache.o)
  "_encode_varint", referenced from:
      _write_untracked_extension in libgit.a[x86_64][63](dir.o)
      _write_untracked_extension in libgit.a[x86_64][63](dir.o)
      _write_untracked_extension in libgit.a[x86_64][63](dir.o)
      _write_one_dir in libgit.a[x86_64][63](dir.o)
      _write_one_dir in libgit.a[x86_64][63](dir.o)
      _do_write_index in libgit.a[x86_64][174](read-cache.o)
ld: symbol(s) not found for architecture x86_64

While it is curious why these functions are needed at all (osxkeychain
does not read or write the index), the compile error is a real problem.

Instead of trying to play games to add `GITLIBS` while filtering out
`common-main.o`, replace the `$(LIB_FILE) $(EXTLIBS)` construct with the
much shorter `$(LIBS)` construct that _already_ filters out
`common-main.o` and adds the Rust library when needed.

Signed-off-by: Johannes Schindelin <redacted>
Signed-off-by: Junio C Hamano <redacted>
6 weeks agotopic flush before -rc1 (batch 2)
Junio C Hamano [Tue, 16 Jun 2026 16:00:37 +0000 (09:00 -0700)]
topic flush before -rc1 (batch 2)

Signed-off-by: Junio C Hamano <redacted>
6 weeks agoMerge branch 'ta/typofixes'
Junio C Hamano [Tue, 16 Jun 2026 16:01:03 +0000 (09:01 -0700)]
Merge branch 'ta/typofixes'

Typofixes

* ta/typofixes:
  docs: fix typos

6 weeks agoMerge branch 'mm/subprocess-handshake-fix'
Junio C Hamano [Tue, 16 Jun 2026 16:01:03 +0000 (09:01 -0700)]
Merge branch 'mm/subprocess-handshake-fix'

The subprocess handshake during startup has been made gentler by using
packet_read_line_gently() instead of packet_read_line() to prevent the
parent Git process from dying abruptly when a configured subprocess
(e.g., a clean/smudge filter) fails to start.

* mm/subprocess-handshake-fix:
  sub-process: use gentle handshake to avoid die() on startup failure

6 weeks agoMerge branch 'wy/docs-typofixes'
Junio C Hamano [Tue, 16 Jun 2026 16:01:02 +0000 (09:01 -0700)]
Merge branch 'wy/docs-typofixes'

Various typos, grammatical errors, and duplicated words in both
documentation and code comments have been corrected.

* wy/docs-typofixes:
  docs: fix typos and grammar

6 weeks agoMerge branch 'jd/unpack-trees-wo-the-repository'
Junio C Hamano [Tue, 16 Jun 2026 16:01:02 +0000 (09:01 -0700)]
Merge branch 'jd/unpack-trees-wo-the-repository'

A handful of inappropriate uses of the_repository have been
rewritten to use the right repository structure instance in the
unpack-trees.c codepath.

* jd/unpack-trees-wo-the-repository:
  unpack-trees: use repository from index instead of global

6 weeks agoMerge branch 'ps/t7527-fix-tap-output'
Junio C Hamano [Tue, 16 Jun 2026 16:01:02 +0000 (09:01 -0700)]
Merge branch 'ps/t7527-fix-tap-output'

A recent regression in t7527 that broke TAP output has been fixed,
some other test noise that also broke TAP output has been silenced,
and 'prove' is now configured to fail on invalid TAP output to
prevent future regressions.

* ps/t7527-fix-tap-output:
  t: let prove fail when parsing invalid TAP output
  t/lib-git-p4: silence output when killing p4d and its watchdog
  t/test-lib: silence EBUSY errors on Windows during test cleanup
  t7810: turn MB_REGEX check into a lazy prereq
  t7527: fix broken TAP output
  ci: unify Linux images across GitLab and GitHub
  gitlab-ci: add missing Linux jobs
  gitlab-ci: rearrange Linux jobs to match GitHub's order

6 weeks agoMerge branch 'jk/describe-contains-all-match-fix'
Junio C Hamano [Tue, 16 Jun 2026 16:01:02 +0000 (09:01 -0700)]
Merge branch 'jk/describe-contains-all-match-fix'

The 'git describe --contains --all' command has been fixed to
properly honor the '--match' and '--exclude' options by passing
them down to 'git name-rev' with the appropriate reference
prefixes.

* jk/describe-contains-all-match-fix:
  describe: fix --exclude, --match with --contains and --all

6 weeks agoMerge branch 'kk/streaming-walk-pqueue'
Junio C Hamano [Tue, 16 Jun 2026 16:01:02 +0000 (09:01 -0700)]
Merge branch 'kk/streaming-walk-pqueue'

Streaming revision walks have been optimized by using a priority queue
for date-sorting commits, speeding up walks repositories with many
merges.

* kk/streaming-walk-pqueue:
  revision: use priority queue for non-limited streaming walks
  revision: introduce rev_walk_mode to clarify get_revision_1()
  pack-objects: call release_revisions() after cruft traversal

6 weeks agoMerge branch 'mf/revision-max-count-oldest'
Junio C Hamano [Tue, 16 Jun 2026 16:01:02 +0000 (09:01 -0700)]
Merge branch 'mf/revision-max-count-oldest'

"git rev-list" (and "git log" family of commands) learned a new "--max-count-oldest"
that picks oldest N commits in the range instead of the usual newest.

* mf/revision-max-count-oldest:
  bash-completions: add --max-count-oldest
  revision.c: implement --max-count-oldest

6 weeks agoMerge branch 'js/win-kill-child-more-gently'
Junio C Hamano [Tue, 16 Jun 2026 16:01:02 +0000 (09:01 -0700)]
Merge branch 'js/win-kill-child-more-gently'

Advanced emulation of kill() used on Windows in GfW has been
upstreamed to improve the symptoms like left-behind .lock files and
that fails to let the child clean-up itself when it gets killed.

* js/win-kill-child-more-gently:
  mingw: really handle SIGINT
  mingw: kill child processes in a gentler way

7 weeks agogitattributes: fix eol attribute for Perl scripts
Koutian Wu [Mon, 15 Jun 2026 07:53:58 +0000 (07:53 +0000)]
gitattributes: fix eol attribute for Perl scripts

The *.pl pattern currently sets eof=lf, which is not a built-in
attribute used for line-ending normalization.

Use eol=lf instead, matching the neighboring *.perl and *.pm rules, so
Perl scripts are checked out with LF line endings.

Signed-off-by: Koutian Wu <redacted>
Signed-off-by: Junio C Hamano <redacted>
7 weeks agoodb: use size_t for object_info.sizep and the size APIs
Johannes Schindelin [Mon, 15 Jun 2026 11:52:29 +0000 (11:52 +0000)]
odb: use size_t for object_info.sizep and the size APIs

When `js/objects-larger-than-4gb-on-windows` widened the streaming,
index-pack and unpack-objects code paths, in the interest of keeping the
patches somewhat reasonably-sized, it left the public ODB API still
typed in `unsigned long`. In particular `struct object_info::sizep` and
the four wrappers built on top of it (`odb_read_object`,
`odb_read_object_peeled`, `odb_read_object_info`, `odb_pretend_object`)
still return the unpacked size through `unsigned long *`, so on Windows
`cat-file -s` and the `git add` / `git status` paths for a >4 GiB blob
silently cap at 4 GiB.

Widen the field and the four wrappers. The previous commits already
widened the `unpack_entry()` cascade and pack-objects' in-core size
accessors, so most of the cascade arrives here with no further work: the
temporary shims in `packed_object_info_with_index_pos()` and in
`unpack_entry()`'s delta-base recovery path go away, the two
`SET_SIZE(entry, cast_size_t_to_ulong(canonical_size))` calls in
`check_object()` and the matching one in `drop_reused_delta()` collapse
to plain `SET_SIZE`, and `oe_get_size_slow()`'s tail
`cast_size_t_to_ulong()` is gone too.

What remains narrow are the boundaries this series does not
intend to touch: the diff, blame, textconv and fast-import machinery.

Even so, this patch is unfortunately quite large.

Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <redacted>
Signed-off-by: Junio C Hamano <redacted>
7 weeks agopackfile,delta: drop the `cast_size_t_to_ulong()` wrappers
Johannes Schindelin [Mon, 15 Jun 2026 11:52:28 +0000 (11:52 +0000)]
packfile,delta: drop the `cast_size_t_to_ulong()` wrappers

When I started the transition from `unsigned long` to `size_t`, in the
interest of keeping the patches reviewable, I introduced these calls to
prevent data type narrowing from silently failing to handle large object
sizes. I also introduced `*_sz()` variants that would allow most of the
callers to keep using that `unsigned long` that the 90s kindly asked to
be returned.

After the preceding commits, the only places that called the narrow
wrappers either no longer exist or already use the `_sz` form
internally, so the wrappers just narrow values back through
`cast_size_t_to_ulong()` for no reason.

Drop them and rename the `_sz` variants back to the natural names.

Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <redacted>
Signed-off-by: Junio C Hamano <redacted>
7 weeks agopack-objects: use size_t for in-core object sizes
Johannes Schindelin [Mon, 15 Jun 2026 11:52:27 +0000 (11:52 +0000)]
pack-objects: use size_t for in-core object sizes

`pack-objects` stores per-entry object sizes in either the 31-bit
`size_` member of the `struct object_entry` or, when the value does not
fit, the `pack->delta_size[]` spill array.  The accessors (`oe_size`,
`oe_delta_size`, `oe_get_size_slow`, `oe_size_*_than`) and the setters
(`oe_set_size`, `oe_set_delta_size`) used `unsigned long` for the spill
type, which on Windows means the spill silently caps at 4 GiB per entry.
That is what made `upload-pack` die with "object too large to read on
this platform" when serving the >4 GiB blob in `t5608` tests 5 and 6
when run with `GIT_TEST_CLONE_2GB`.

Widen them all to `size_t` (including `pack->delta_size`) and drop the
three `cast_size_t_to_ulong()` calls in `check_object()` that guarded
`in_pack_size`.  The two `SET_SIZE(entry, canonical_size)` calls in the
same function stay cast-free as before, since `canonical_size` is still
`unsigned long` until a later commit widens `object_info::sizep`.

Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <redacted>
Signed-off-by: Junio C Hamano <redacted>
7 weeks agopackfile: widen unpack_entry()'s size out-parameter to size_t
Johannes Schindelin [Mon, 15 Jun 2026 11:52:26 +0000 (11:52 +0000)]
packfile: widen unpack_entry()'s size out-parameter to size_t

The topic `js/objects-larger-than-4gb-on-windows` widened the streaming,
index-pack and unpack-objects paths to `size_t` but deliberately stopped
at the in-memory `unpack_entry()` cascade, which still hands back the
unpacked size through `unsigned long *`.  On Windows that boundary
truncates above 4 GiB because that data type is only 32 bits wide on
that platform.

Widen the code path. Except `packed_object_info_with_index_pos()`: It
cannot yet pass `oi->sizep` directly because the field is still
`unsigned long *`; bridge it with a `size_t` temporary that narrows
back, and let a later commit drop the bridge once the field is wide
too. `gfi_unpack_entry()` keeps its narrow signature because fast-import
tracks sizes through `unsigned long` everywhere it crosses subsystem
boundaries, keeping its signature allows the scope of this commit to be
somewhat reasonable, still.

Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <redacted>
Signed-off-by: Junio C Hamano <redacted>
7 weeks agopack-objects(check_pack_inflate()): use size_t instead of unsigned long
Johannes Schindelin [Mon, 15 Jun 2026 11:52:25 +0000 (11:52 +0000)]
pack-objects(check_pack_inflate()): use size_t instead of unsigned long

`write_reuse_object()` learned to track its packed-object size as
`size_t` in 606c192380 (odb, packfile: use size_t for streaming
object sizes, 2026-05-08), but the comparison sink it feeds,
`check_pack_inflate()`, still takes the expected decompressed size
as `unsigned long`. The call site bridges the mismatch with
`cast_size_t_to_ulong()`, which on Windows turns a >4 GiB object
into an immediate die().

That function only uses `expect` once: as the right-hand side of a
`stream.total_out == expect` equality test against zlib's counter.
zlib's own `total_out` counter is `uLong` and is therefore still
32-bit-bound on Windows. Widening `expect` to `size_t` cannot fix that,
but it is a strict improvement nonetheless: instead of dying outright,
an oversized object now simply makes the equality fail and lets
`write_reuse_object()` fall back to `write_no_reuse_object()`, which
decompresses and re-deflates the content (and which the larger
pack-objects widening series targets separately).

Drop the `cast_size_t_to_ulong()` shim at the call site now that
the receiving parameter speaks the same type as `entry_size`.

Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <redacted>
Signed-off-by: Junio C Hamano <redacted>
7 weeks agopatch-delta: use size_t for sizes
Johannes Schindelin [Mon, 15 Jun 2026 11:52:24 +0000 (11:52 +0000)]
patch-delta: use size_t for sizes

`patch_delta()` takes the source and delta sizes by value and writes
back the reconstructed target size through an `unsigned long *`.  That
datatype cannot represent a value that exceeds 4 GiB on systems where
`unsigned long` is 32-bit (notably 64-bit Windows builds), though, even
though the delta encoding itself, the on-disk layout, and the in-memory
buffers happily carry such sizes. A `size_t` companion to
`get_delta_hdr_size()`, `get_delta_hdr_size_sz()`, was introduced in
17fa077596 (delta, packfile: use size_t for delta header sizes,
2026-05-08) precisely so that `patch_delta()` could be widened without
changing the on-the-wire decoding helper's signature.

Widen `patch_delta()`'s three size parameters to `size_t` and switch
its internal use of `get_delta_hdr_size()` to the `_sz` variant.
Then propagate the wider type through the callers.

Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <redacted>
Signed-off-by: Junio C Hamano <redacted>
7 weeks agocompat/msvc: use _chsize_s for ftruncate
Johannes Schindelin [Mon, 15 Jun 2026 11:52:23 +0000 (11:52 +0000)]
compat/msvc: use _chsize_s for ftruncate

On Windows, `unsigned long` and `long` are 32 bits even on 64-bit
builds. The MSVC compatibility header has shimmed `ftruncate()` with

#define ftruncate _chsize

ever since `compat/msvc-posix.h` was introduced. `_chsize()` takes a
32-bit `long` for the new length, which silently truncates files (and
the requested size) to 2 GiB. That is enough to make t7508 test 126
"git add fails gracefully with 4 GiB and 8 GiB files" fail under
MSVC: `test-tool truncate` creates a sparse 4 GiB or 8 GiB file via
the shimmed `ftruncate()`, and the test never gets off the ground.

`_chsize_s()` is the modern replacement, accepts a 64-bit `__int64`
length, and is the only sensible target on Windows. The catch is that
it does not follow the POSIX `-1` + `errno` convention: it returns
`0` on success and an errno value (a small positive integer) on
failure. A plain `#define ftruncate _chsize_s` would therefore
silently break callers that test the return value as `< 0` or against
`-1`, of which there are several: `http.c`, `parallel-checkout.c`,
and `t/helper/test-truncate.c` among them.

Introduce a `static inline` wrapper that calls `_chsize_s()`, copies
its errno return into `errno`, and translates the result to the
familiar `-1` / `0` convention, then point `ftruncate` at the
wrapper. Place the wrapper after `#include "mingw-posix.h"` so the
`off_t` parameter resolves to the already-widened `off64_t` rather
than the 32-bit `_off_t` from `compat/vcbuild/include/unistd.h`.

MinGW is unaffected: its `ftruncate()` already takes `off_t` and
routes through `ftruncate64()` when `_FILE_OFFSET_BITS=64`, which is
the default in our build.

Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <redacted>
Signed-off-by: Junio C Hamano <redacted>
7 weeks agotopic flush before -rc1 (batch 1)
Junio C Hamano [Mon, 15 Jun 2026 14:41:33 +0000 (07:41 -0700)]
topic flush before -rc1 (batch 1)

Signed-off-by: Junio C Hamano <redacted>
7 weeks agoMerge branch 'ak/typofixes'
Junio C Hamano [Mon, 15 Jun 2026 14:42:00 +0000 (07:42 -0700)]
Merge branch 'ak/typofixes'

Typofixes.

* ak/typofixes:
  doc: fix typos via codespell

7 weeks agoMerge branch 'ob/more-repo-config-values'
Junio C Hamano [Mon, 15 Jun 2026 14:42:00 +0000 (07:42 -0700)]
Merge branch 'ob/more-repo-config-values'

Many core configuration variables have been migrated from global
variables into 'repo_config_values' to tie them to a specific
repository instance, avoiding cross-repository state leakage.

* ob/more-repo-config-values:
  environment: move "warn_on_object_refname_ambiguity" into `struct repo_config_values`
  environment: move "sparse_expect_files_outside_of_patterns" into `struct repo_config_values`
  environment: move "core_sparse_checkout_cone" into `struct repo_config_values`
  environment: move "precomposed_unicode" into `struct repo_config_values`
  environment: move "pack_compression_level" into `struct repo_config_values`
  environment: move `zlib_compression_level` into `struct repo_config_values`
  environment: move "check_stat" into `struct repo_config_values`
  environment: move "trust_ctime" into `struct repo_config_values`

7 weeks agoMerge branch 'am/doc-tech-hash-typofix'
Junio C Hamano [Mon, 15 Jun 2026 14:42:00 +0000 (07:42 -0700)]
Merge branch 'am/doc-tech-hash-typofix'

Typofix.

* am/doc-tech-hash-typofix:
  doc: fix typo in GIT_ALTERNATE_OBJECT_DIRECTORIES

7 weeks agoMerge branch 'lo/doc-format-patch-subject-prefix'
Junio C Hamano [Mon, 15 Jun 2026 14:42:00 +0000 (07:42 -0700)]
Merge branch 'lo/doc-format-patch-subject-prefix'

Wording used in "format-patch --subject-prefix" documentation
has been improved.

* lo/doc-format-patch-subject-prefix:
  Documentation: remove redundant 'instead' in --subject-prefix

7 weeks agoMerge branch 'ps/setup-centralize-odb-creation'
Junio C Hamano [Mon, 15 Jun 2026 14:41:59 +0000 (07:41 -0700)]
Merge branch 'ps/setup-centralize-odb-creation'

The setup logic to discover and configure repositories has been
refactored, and the initialization of the object database has been
centralized.

* ps/setup-centralize-odb-creation:
  setup: construct object database in `apply_repository_format()`
  repository: stop reading loose object map twice on repo init
  setup: stop initializing object database without repository
  setup: stop creating the object database in `setup_git_env()`
  repository: stop initializing the object database in `repo_set_gitdir()`
  setup: deduplicate logic to apply repository format
  setup: drop `setup_git_env()`
  t0001: plug test gaps for git-init(1) with GIT_OBJECT_DIRECTORY

7 weeks agoMerge branch 'hn/config-typo-advice'
Junio C Hamano [Mon, 15 Jun 2026 14:41:59 +0000 (07:41 -0700)]
Merge branch 'hn/config-typo-advice'

"git config foo.bar=baz" is not likely to be a request to read the
value of such a variable with '=' in its name; rather it is plausible
that the user meant "git config set foo.bar baz".  Give advice when
giving an error message.

* hn/config-typo-advice:
  config: improve diagnostic for "set" with missing value
  config: add git_config_key_is_valid() for quiet validation

7 weeks agoMerge branch 'ls/doc-raw-timestamp-prefix'
Junio C Hamano [Mon, 15 Jun 2026 14:41:59 +0000 (07:41 -0700)]
Merge branch 'ls/doc-raw-timestamp-prefix'

Documentation and tests have been added to clarify that Git's internal
raw timestamp format requires a `@` prefix for values less than
100,000,000 to prevent ambiguity with other formats like YYYYMMDD.

* ls/doc-raw-timestamp-prefix:
  doc: document and test `@` prefix for raw timestamps

7 weeks agoMerge branch 'jc/submitting-patches-cover-letter'
Junio C Hamano [Mon, 15 Jun 2026 14:41:59 +0000 (07:41 -0700)]
Merge branch 'jc/submitting-patches-cover-letter'

Guidelines on how to write a cover letter for a multi-patch series
have been added to SubmittingPatches, which also got a new marker
to separate the section for typofixes.

* jc/submitting-patches-cover-letter:
  SubmittingPatches: describe cover letter
  SubmittingPatches: separate typofixes section

7 weeks agocommit-graph: use timestamp_t for max parent generation accumulator
Elijah Newren [Sun, 14 Jun 2026 06:57:50 +0000 (06:57 +0000)]
commit-graph: use timestamp_t for max parent generation accumulator

compute_reachable_generation_numbers() computes each commit's
generation as

    max(c->date, max(parent.generation)) + 1

by walking its parents and accumulating their generations into a
local

    uint32_t max_gen = 0;

while info->get_generation() returns timestamp_t and
compute_generation_from_max() already takes its max_gen parameter
as timestamp_t.  For v1 (topological levels) the narrowing is
harmless because GENERATION_NUMBER_V1_MAX is less than 2^30, but
for v2 (corrected committer dates) it silently truncates any
parent generation that does not fit in 32 bits, i.e. any parent
whose committer timestamp is at or beyond 2106-02-07 UTC
(>= 2^32).

The truncated max then causes child commits to end up with a
corrected committer date that matches the parent's instead of being
at least 1 higher.  The bad value gets written into the commit-graph
and causes problems later, and can be noticed by running `git
commit-graph verify`.

Widen the accumulator to timestamp_t.

This is solely an in-memory arithmetic fix with no on-disk format
change: the on-disk format already encodes timestamp_t values and
existing readers handle them unchanged.  This merely allows the code to
compute the correct value to write to disk.

The narrowing was introduced in 80c928d947c2 (commit-graph:
simplify compute_generation_numbers(), 2023-03-20), which rewired
v2 to use the shared compute_reachable_generation_numbers()
helper; the helper's local accumulator had been declared uint32_t
in the immediately preceding 368d19b0b7fa (commit-graph: refactor
compute_topological_levels(), 2023-03-20) when only v1 was using
it, where it was harmless.

Add a new test with a future-dated parent and a present-day child;
without the above fix, `git commit-graph verify` reports the
descendant's stored generation as below parent + 1.

Signed-off-by: Elijah Newren <redacted>
Signed-off-by: Junio C Hamano <redacted>
7 weeks agocompat/posix.h: simplify GIT_GNUC_PREREQ() comparison
Dominik Loidolt [Sat, 13 Jun 2026 12:27:11 +0000 (14:27 +0200)]
compat/posix.h: simplify GIT_GNUC_PREREQ() comparison

GIT_GNUC_PREREQ() uses a glibc-style bit-shift version comparison,
which is harder to read than an explicit major/minor comparison.

Use an explicit comparison, as in many BSD <sys/cdefs.h> headers, and
drop the Linux header attribution comment because it no longer applies.

Signed-off-by: Dominik Loidolt <redacted>
Signed-off-by: Junio C Hamano <redacted>
git clone https://git.99rst.org/PROJECT