After releasing v2.2.6, they followed up really quickly with a v2.2.7,
which indicates some urgency in taking this update. The diff of this PR
is pretty informative, too.
This closes https://github.com/git-for-windows/git/issues/6046
In MSYS2, we have two Python interpreters at our disposal, so we can
include the Python stuff in the build.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The vendored nedmalloc allocator under compat/nedmalloc/ has been
unmaintained upstream for a very long time: the original repository at
https://github.com/ned14/nedmalloc received its last commit on July 5,
2014, and was archived (made read-only) by its owner on March 15, 2019.
Our copy has been carried forward unchanged ever since.
The Git for Windows commit that introduced mimalloc as a replacement
on Windows ("mingw: use mimalloc", 2019-06-24, present in the Git for
Windows branch thicket but not upstream) already observed at that time
that nedmalloc had ceased to see any updates for several years.
This came to a head when the Git for Windows SDK upgraded to GCC 16:
the `add_segment()` function in `compat/nedmalloc/malloc.c.h` declares
`int nfences = 0` and only references it inside an `assert()`, which
GCC 16 now flags as `-Wunused-but-set-variable`. Combined with the
`-Werror` enabled by `DEVELOPER=1`, this turns into a hard build
failure:
compat/nedmalloc/malloc.c.h: In function 'add_segment':
compat/nedmalloc/malloc.c.h:3897:7: error: variable 'nfences' set but not used [-Werror=unused-but-set-variable=]
3897 | int nfences = 0;
| ^~~~~~~
cc1.exe: all warnings being treated as errors
The same source built without complaint under GCC 15.2.0; the
regression was bisected to the SDK package update at
https://github.com/git-for-windows/git-sdk-64/commit/188d93dd455
(`mingw-w64-x86_64-gcc 15.2.0-14 -> 16.1.0-1`), with the failing CI
run captured at
https://github.com/git-for-windows/git-sdk-64/actions/runs/25244795074.
Rather than patch the unmaintained vendored sources to silence the
warning, stop opting into nedmalloc altogether on MINGW. The platform
allocator is what every non-MINGW build already uses, and a fresh
build of git.git's master against a minimal Git for Windows SDK
upgraded to GCC 16, with `USE_NED_ALLOCATOR` removed from the MINGW
section, completes successfully.
The compat/nedmalloc/ subtree itself is left in place to keep this
change minimal; nothing in the build links against it any longer, so
it can be removed in a follow-up if desired.
Assisted-by: Claude Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This topic branch allows us to specify absolute paths without the drive
prefix e.g. when cloning.
Example:
C:\Users\me> git clone https://github.com/git/git \upstream-git
This will clone into a new directory C:\upstream-git, in line with how
Windows interprets absolute paths.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
These fixes were necessary for Sverre Rabbelier's remote-hg to work,
but for some magic reason they are not necessary for the current
remote-hg. Makes you wonder how that one gets away with it.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Update clink.pl to link with either libcurl.lib or libcurl-d.lib
depending on whether DEBUG=1 is set.
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
In 1e64d18 (mingw: do resolve symlinks in `getcwd()`) a problem was
introduced that causes git for Windows to stop working with certain
mapped network drives (in particular, drives that are mapped to
locations with long path names). Error message was "fatal: Unable to
read current working directory: No such file or directory". Present
change fixes this issue as discussed in
https://github.com/git-for-windows/git/issues/2480
Signed-off-by: Bjoern Mueller <bjoernm@gmx.de>
Since commit 0c499ea60f (send-pack: demultiplex a sideband stream with
status data, 2010-02-05) the send-pack builtin uses the side-band-64k
capability if advertised by the server.
Unfortunately this breaks pushing over the dump git protocol if used
over a network connection.
The detailed reasons for this breakage are (by courtesy of Jeff Preshing,
quoted from https://groups.google.com/d/msg/msysgit/at8D7J-h7mw/eaLujILGUWoJ):
MinGW wraps Windows sockets in CRT file descriptors in order to
mimic the functionality of POSIX sockets. This causes msvcrt.dll
to treat sockets as Installable File System (IFS) handles,
calling ReadFile, WriteFile, DuplicateHandle and CloseHandle on
them. This approach works well in simple cases on recent
versions of Windows, but does not support all usage patterns. In
particular, using this approach, any attempt to read & write
concurrently on the same socket (from one or more processes)
will deadlock in a scenario where the read waits for a response
from the server which is only invoked after the write. This is
what send_pack currently attempts to do in the use_sideband
codepath.
The new config option `sendpack.sideband` allows to override the
side-band-64k capability of the server, and thus makes the dumb git
protocol work.
Other transportation methods like ssh and http/https still benefit from
the sideband channel, therefore the default value of `sendpack.sideband`
is still true.
Signed-off-by: Thomas Braun <thomas.braun@byte-physics.de>
Signed-off-by: Oliver Schneider <oliver@assarbad.net>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
While Git for Windows does not _ship_ Python (in order to save on
bandwidth), MSYS2 provides very fine Python interpreters that users can
easily take advantage of, by using Git for Windows within its SDK.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
On Windows, there are several categories of absolute paths. One such
category starts with a backslash and is implicitly relative to the drive
associated with the current working directory. Example:
c:
git clone https://github.com/git-for-windows/git \G4W
should clone into C:\G4W.
Back in 2017, Juan Carlos Arevalo Baeza reported a bug in Git's handling
of those absolute paths was identified, and fixed. Let's make sure that
it stays fixed.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
These fixes have been sent to the Git mailing list but have not been
picked up by the Git project yet.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
After importing anything with fast-import, we should always let the
garbage collector do its job, since the objects are written to disk
inefficiently.
This brings down an initial import of http://selenic.com/hg from about
230 megabytes to about 14.
In the future, we may want to make this configurable on a per-remote
basis, or maybe teach fast-import about it in the first place.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
In some implementations, `regexec_buf()` assumes that it is fed lines;
Without `REG_NOTEOL` it thinks the end of the buffer is the end of a
line. Which makes sense, but trips up this case because we are not
feeding lines, but rather a whole buffer. So the final newline is not
the start of an empty line, but the true end of the buffer.
This causes an interesting bug:
$ echo content >file.txt
$ git grep --no-index -n '^$' file.txt
file.txt:2:
This bug is fixed by making the end of the buffer consistently the end
of the final line.
The patch was applied from
https://lore.kernel.org/git/20250113062601.GD767856@coredump.intra.peff.net/
Reported-by: Olly Betts <olly@survex.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This addresses:
- CVE-2024-52005:
Insufficient neutralization of ANSI escape sequences in sideband
payload can be used to mislead Git users into believing that
certain remote-generated messages actually originate from Git.
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
When a Unix socket is initialized, the current directory's path is
stored so that the cleanup code can `chdir()` back to where it was
before exit.
If the path that needs to be stored exceeds the default size of the
`sun_path` attribute of `struct sockaddr_un` (which is defined as a
108-sized byte array on Linux), a larger buffer needs to be allocated so
that it can hold the path, and it is the responsibility of the
`unix_sockaddr_cleanup()` function to release that allocated memory.
In Git's CI, this stack allocation is not necessary because the code is
checked out to `/home/runner/work/git/git`. Concatenate the path
`t/trash directory.t0301-credential-cache/.cache/git/credential/socket`
and a terminating NUL, and you end up with 96 bytes, 12 shy of the
default `sun_path` size.
However, I use worktrees with slightly longer paths:
`/home/me/projects/git/yes/i/nest/worktrees/to/organize/them/` is more
in line with what I have. When I recently tried to locally reproduce a
failure of the `linux-leaks` CI job, this t0301 test failed (where it
had not failed in CI).
The reason: When `credential-cache` tries to reach its daemon initially
by calling `unix_sockaddr_init()`, it is expected that the daemon cannot
be reached (the idea is to spin up the daemon in that case and try
again). However, when this first call to `unix_sockaddr_init()` fails,
the code returns early from the `unix_stream_connect()` function
_without_ giving the cleanup code a chance to run, skipping the
deallocation of above-mentioned path.
The fix is easy: do not return early but instead go directly to the
cleanup code.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The preceding two commits introduced special handling of the sideband
channel to neutralize ANSI escape sequences before sending the payload
to the terminal, and `sideband.allowControlCharacters` to override that
behavior.
However, some `pre-receive` hooks that are actively used in practice
want to color their messages and therefore rely on the fact that Git
passes them through to the terminal.
In contrast to other ANSI escape sequences, it is highly unlikely that
coloring sequences can be essential tools in attack vectors that mislead
Git users e.g. by hiding crucial information.
Therefore we can have both: Continue to allow ANSI coloring sequences to
be passed to the terminal, and neutralize all other ANSI escape
sequences.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
On Windows, symbolic links come in two flavors: file symlinks and
directory symlinks. Since Git was born on Linux where this distinction
does not exist, Git for Windows has to auto-detect the type by looking
at the target. When the target does not yet exist at symlink creation
time, Git for Windows creates a "phantom" file symlink and later, once
checkout is complete, calls `CreateFileW()` on the target to check
whether it is actually a directory.
If the symlink target is a UNC path (e.g. `\\attacker\share`), this
auto-detection triggers an SMB connection to the remote host. Windows
performs NTLM authentication by default for such connections, which
means a crafted repository can exfiltrate the cloning user's NTLMv2
hash to an attacker-controlled server without any user interaction
beyond `git clone -c core.symlinks=true <url>`.
There are ways to specify UNC paths that start with only a single
backslash (e.g. `\??\UNC\host\share`); All of them do start like
that, though, so let's use that as a tell-tale that we should skip
the auto-detection in `process_phantom_symlink()`. The symlink is
then left as a file symlink (the `mklink` default), and a warning is
emitted suggesting the user set the `symlink` gitattribute to `dir`
if a directory symlink is needed. When the attribute is already set,
auto-detection is never invoked in the first place, so that code path
is unaffected.
This is the same class of vulnerability as CVE-2025-66413
(https://github.com/git-for-windows/git/security/advisories/GHSA-hv9c-4jm9-jh3x)
and follows the same general mitigation pattern that MinTTY adopted for
ANSI escape sequences referencing network share paths
(https://github.com/mintty/mintty/security/advisories/GHSA-jf4m-m6rv-p6c5).
Note that there are legitimate paths starting with a single backslash
that are _not_ network paths: drive-less absolute paths are interpreted
as relative to the current working directory's drive. In practice, these
are highly uncommon (and brittle, just one working directory change
away from breaking). In any case, the only consequence is now that the
symlink type of those has to be specified via Git attributes, is all.
Reported-by: Justin Lee <jessdhoctor@gmail.com>
Addresses: CVE-2026-32631
Addresses: https://github.com/git-for-windows/git/security/advisories/GHSA-9j5h-h4m7-85hx
Assisted-by: Claude Opus 4.6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This happens only when the corresponding commits are not exported in
the current fast-export run. This can happen either when the relevant
commit is already marked, or when the commit is explicitly marked
as UNINTERESTING with a negative ref by another argument.
This breaks fast-export basec remote helpers.
Signed-off-by: Sverre Rabbelier <srabbelier@gmail.com>
The preceding commit fixed the vulnerability whereas sideband messages
(that are under the control of the remote server) could contain ANSI
escape sequences that would be sent to the terminal verbatim.
However, this fix may not be desirable under all circumstances, e.g.
when remote servers deliberately add coloring to their messages to
increase their urgency.
To help with those use cases, give users a way to opt-out of the
protections: `sideband.allowControlCharacters`.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Every once in a while I need to verify that Microsoft Git's test suite
passes for changes that are not yet meant for public consumption, and
since it was (made) too difficult to keep up a working Azure Pipeline
definition, I have to use GitHub Actions in a private GitHub repository
for that purpose.
In these tests, basically all Dockerized CI jobs fail consistently. The
symptom is something like:
error: cannot create async thread: Resource temporarily unavailable
in the middle of a test, typically in the t5xxx-t6xxx range. The first
such error is immediately followed by plenty more of these errors, and
not a single test succeeds afterwards.
At first, I thought that maybe the massive parallelism I enjoy there is
the problem, and I thought that the cgroups limits might be shared
between the many containers that run on essentially the same physical
machine. But even reducing the matrix to just a single of those
Dockerized jobs runs into the very same problems.
The underlying reason seems to be a substantial difference in the hosted
runners that execute these Dockerized jobs: forcing the PID limit of the
container to a high number lets the jobs pass, even when running the
complete matrix of all 13 Dockerized jobs concurrently. But that's not
the only difference: The jobs seem to take a lot longer in these
containers than, say, in the containers made available to
https://github.com/git/git.
When forcing a PID limit of 64k in that private repository, the jobs
completed successfully, but they also took a lot longer, between 2x to
2.5x longer, i.e. painfully much longer. Reducing the PID limit to 16k,
the CI jobs still passed, but took an equally long amount of time.
Reducing the PID limit to 8k caused the errors to reappear.
Here are the numbers from three example runs, the first one forcing the
PID and nproc limit to 65536, the second one to 16384, the third run is
from the public git/git repository:
Job | 64k | 16k | reference
------------------------------|---------|---------|---------
almalinux-8 | 19m 3s | 16m 0s | 9m 36s
debian-11 | 20m 31s | 20m 3s | 8m 5s
fedora-breaking-changes-meson | 16m 29s | 19m 19s | 9m 40s
linux-asan-ubsan | 1h 10m | 1h 11m | 34m 36s
linux-breaking-changes | 25m 39s | 25m 58s | 13m 15s
linux-leaks | 1h 9m | 1h 10m | 33m 30s
linux-meson | 28m 9s | 27m 4s | 13m 45s
linux-musl-meson | 16m 32s | 13m 39s | 8m 6s
linux-reftable-leaks | 1h 13m | 1h 13m | 34m 34s
linux-reftable | 26m 2s | 25m 48s | 13m 31s
linux-sha256 | 26m 12s | 26m 3s | 12m 36s
linux-TEST-vars | 26m 5s | 25m 21s | 13m 25s
linux32 | 21m 16s | 19m 57s | 10m 44s
It does not look as if the PID limit is the reason for the longer
runtime, seeing as the 64k vs 16k timings deviate no more than as is
usual with GitHub workflows. So let's go for 16k.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The output of `git clone` is a vital component for understanding what
has happened when things go wrong. However, these logs are partially
under the control of the remote server (via the "sideband", which
typically contains what the remote `git pack-objects` process sends to
`stderr`), and is currently not sanitized by Git.
This makes Git susceptible to ANSI escape sequence injection (see
CWE-150, https://cwe.mitre.org/data/definitions/150.html), which allows
attackers to corrupt terminal state, to hide information, and even to
insert characters into the input buffer (i.e. as if the user had typed
those characters).
To plug this vulnerability, disallow any control character in the
sideband, replacing them instead with the common `^<letter/symbol>`
(e.g. `^[` for `\x1b`, `^A` for `\x01`).
There is likely a need for more fine-grained controls instead of using a
"heavy hammer" like this, which will be introduced subsequently.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Upstream has landed Patrick Steinhardt's patch [build: tolerate use of
_Generic from glibc 2.43 with
Clang](https://lore.kernel.org/git/xmqqecjischc.fsf@gitster.g) in a form
that differs from what we currently carry as 74c3ea98ed (a cherry-pick
of Patrick's v1). The upstream variant on `next` (commit 0a6d29090c)
carries the trailer `[jc: replaced Makefile side with Shardul's
approach]` and is signed off by Junio.
Concretely, instead of dropping `-std=gnu99` for Clang in
`config.mak.dev`, the upstream variant keeps `-std=gnu99` and adds
`-Wno-c11-extensions` for Clang in a dedicated top-level block,
mirroring what Patrick already did on the Meson side. Keeping
`-std=gnu99` is desirable because it still lets us catch accidental use
of newer-than-C99 features in Git's own code.
This PR is the amend! commit that brings our downstream pick in line
with that upstream landing. Autosquashing onto the parent of 74c3ea98ed
produces a single commit whose tree state is identical to 0a6d29090c
(modulo our USE_MIMALLOC carry inside the gcc6/clang7 block on the
Makefile side). The intended merge strategy is
autosquash-then-force-push to `main`, not a regular merge commit, so the
history mirrors what landed upstream.
Junio's confirmation that he is fast-tracking the topic to `next` and
`master` is at https://lore.kernel.org/git/xmqqecjischc.fsf@gitster.g.
The `windows-latest` runner image migration that began on June 8, 2026
and completes by June 15, 2026 swaps Visual Studio 2022 for Visual
Studio 2026 by default (see
[actions/runner-images#14017](https://github.com/actions/runner-images/issues/14017)).
That, in turn, leaves the `vs-build` job broken because of two
independent things baked into the workflow.
First, CMake 4.x now picks up the `Visual Studio 18 2026` generator on
this image, and that generator writes a `.slnx` (XML solution) file
rather than the classic `.sln`. The behavior is explicit in
[`cmGlobalVisualStudioGenerator::GetSLNFile`](https://github.com/Kitware/CMake/blob/v4.3.2/Source/cmGlobalVisualStudioGenerator.cxx#L1147-L1159),
which appends `"x"` to the filename whenever the generator version is
`VS18` or newer. The MSBuild step then trips over the missing `git.sln`:
```
MSBUILD : error MSB1009: Project file does not exist.
Switch: git.sln
```
A representative failure is [actions run
27264770241](https://github.com/git-for-windows/git/actions/runs/27264770241/job/80556419519).
Second, the step has been pinning `-property:PlatformToolset=v142` since
[889cacb6](https://github.com/git-for-windows/git/commit/889cacb6)
(2020), when the job was first wired up for Visual Studio 2019. The new
VS 2026 image only ships the v144 toolset plus a v143 compatibility
component (`Microsoft.VisualStudio.Component.VC.14.44.17.14.x86.x64`);
v142 is simply not installed any more, so even after the `.slnx` rename
the pin would fail in its own right.
This PR therefore changes the MSBuild invocation to reference `git.slnx`
and drops the v142 toolset pin, letting MSBuild use whatever toolset
CMake chose during configuration (v144 on the current image). MSBuild
18, which the new image ships, understands `.slnx` natively, so no
further plumbing is needed.
The `windows-latest` runner image migration that began on June 8, 2026
and completes on June 15, 2026 switches the default Visual Studio
install from VS 2022 (v17) to VS 2026 (v18), per
https://github.com/actions/runner-images/issues/14017.
CMake 4.x picks up the new generator name "Visual Studio 18 2026"
automatically and, crucially, writes the solution file with the new
`.slnx` (XML) extension rather than `.sln`. See
https://github.com/Kitware/CMake/blob/v4.3.2/Source/cmGlobalVisualStudioGenerator.cxx#L1147-L1159
where `GetSLNFile()` appends an "x" to the filename when the generator
version is `VS18` or newer.
As a result, the `MSBuild` step in the `vs-build` job fails with
MSBUILD : error MSB1009: Project file does not exist.
Switch: git.sln
because the file CMake actually wrote is `git.slnx`. An example of the
failure can be seen at
https://github.com/git-for-windows/git/actions/runs/27264770241/job/80556419519.
Teach the step to prefer `git.slnx` and fall back to `git.sln` so that
it works on both the new image and any runner still on VS 2022 during
the week-long staggered rollout. The conditional is written in
PowerShell rather than bash so the step stays on the default shell:
`microsoft/setup-msbuild@v3` adds `msbuild` to the Windows `PATH` only,
and an MSYS2 bash spawned by the SDK does not pick it up (an earlier
attempt at this fix using `shell: bash` failed with
`msbuild: command not found`, see
https://github.com/git-for-windows/git/actions/runs/27290221733/job/80608493655).
Letting MSBuild itself discover the solution by omitting the project
argument is not an option here either: CMake emits all `*.vcxproj`
files (one per `add_executable`/`add_library`, e.g.
`git-daemon.vcxproj`, `common-main.vcxproj`, `ALL_BUILD.vcxproj`, ...)
into the same build root as the solution file, and MSBuild's
auto-discovery in
`ProcessProjectSwitch()` (`dotnet/msbuild`, `src/MSBuild/XMake.cs`)
rejects that combination as `AmbiguousProjectError` because it only
disambiguates the special case of exactly two projects where one has a
`.proj` extension.
Additionally, drop the `-property:PlatformToolset=v142` argument that
had been carried since 889cacb6 (ci: configure GitHub Actions for
CI/PR, 2020-04-11), when this job was first configured for VS 2019.
The VS 2026 install on `windows-latest` only ships the v144 toolset
along with a v143 compatibility component
(`Microsoft.VisualStudio.Component.VC.14.44.17.14.x86.x64`); v142 is
no longer present, so the explicit pin would now also fail in its own
right. Removing it lets MSBuild use whatever toolset CMake selected
during configuration (v143 on a VS 2022 runner, v144 on a VS 2026 one),
which keeps the configure and build steps consistent with each other
regardless of which image picked up the job.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Assisted-by: Opus 4.7
## Problem
`git checkout <tree> -- <pathspec>` with `checkout.workers > 1` and
`core.fscache=true` fails when restoring files into directories that do
not yet exist on disk. Two failure modes:
1. `fatal: cannot create directory at '...': Directory not empty` (exit
128)
2. `error: unable to stat just-written file '...'` (exit 255)
100% reproducible when two or more files share a not-yet-created parent
directory.
## Root Cause
The Windows fscache caches directory listings that become stale when
`create_directories()` creates new parent directories via `mkdir()` or
when `write_pc_item()` writes new files. With `workers=1`,
`write_entry()` calls `flush_fscache()` after each file, keeping the
cache in sync. With `workers>1`, `enqueue_checkout()` defers the write
(and the flush), leaving the cache stale for subsequent entries.
## Fix
Add `flush_fscache()` calls:
- In `create_directories()` after each successful `mkdir()`, so
`has_dirs_only_path()` sees the new directory
- In `write_pc_item()` before `lstat()` of the just-written file
On non-Windows platforms `flush_fscache()` is a no-op.
## Test
Adds a regression test to `t2080-parallel-checkout-basics.sh` (`MINGW`
prereq) that deterministically reproduces the bug: two files sharing a
nested parent directory, deleted in a second commit, then restored via
`git checkout <tree> -- <pathspec>` with `workers=2`.
This is a companion of https://github.com/microsoft/git/pull/899.
Trace2 + GIT_TRACE_FSCACHE evidence on Windows ARM64 (Snapdragon X
Elite, ReFS Dev Drive) shows that the heaviest lstat-bound work in git
add happens inside repo_read_index_preload(), which currently runs
before enable_fscache() is called. Moving the enable up so the preload
phase is wrapped lets the existing batched NtQueryDirectoryFile cache
cover the bulk of the lstat traffic. This patch gave me a ~30%
performance improvement on a large git repo with a batched add.
Also at the end of cmd_add(): the cleanup site called enable_fscache(0)
again instead of disable_fscache(), leaking the refcount.
When 6a29c2dfec ("mingw: use mimalloc",
2019-06-24) introduced the vendored mimalloc, the comparison was against
`nedmalloc` (which by then had not seen an upstream commit since 2014,
and whose repository was archived in 2019). The two were essentially at
parity in that benchmark; mimalloc was chosen because it was actively
developed. I do not really recall whether the platform's *default*
allocator was not part of the comparison; If it was, the performance was
still worse than mimalloc, if it wasn't, I forgot to test ;-)
Six years on, with `nedmalloc` safely on its way to being dropped from
the upstream codebase entirely
(https://github.com/gitgitgadget/git/pull/2104, currently in `seen` as
e576abb9f8), the question is no longer "mimalloc vs nedmalloc" but
"mimalloc vs the OS allocator". Re-running the same `git repack -adfq`
benchmark against each platform's current default allocator finds no
measurable speedup from mimalloc on any of Windows, macOS, or Linux.
## Methods
I recapitulated the same benchmark as cited in 6a29c2dfec (the original
comparison was nedmalloc vs mimalloc on `git repack -adfq` over a subset
of `linux.git`), now extended to the three GitHub-hosted runners
(`ubuntu-latest`, `macos-latest`, `windows-latest`). Each job built two
`git` binaries from the same source tree, vanilla and
`USE_MIMALLOC=YesPlease`, then prepared a fresh bare clone of
`linux.git` to a fixed `SHA`, and ran the repacks with both built `git`s
in randomized order for five iterations. Each iteration ran both
binaries exactly once on a freshly `copytree`-ed copy of the immutable
template repository; the order *within* an iteration was randomized so
any per-iteration confounder (cache state, runner warm-up, neighbour-VM
contention) would be shared symmetrically between variants. Timings
excluded the `copytree`. The full driver is the Python script
`ci/bench-mimalloc.py` on the [`mimalloc-benchmark`
branch](https://github.com/dscho/git/tree/mimalloc-benchmark/ci).
## Results: original `linux v2.6.20`-era workload (49,917 commits,
431,605 objects, ~204 MB pack)
| Platform | vanilla mean ± stdev | mimalloc mean ± stdev | Δ (mimalloc
− vanilla) |
|---|---|---|---|
| `ubuntu-latest` | 27.089s ± 0.060s | 27.041s ± 0.065s | −0.048s
(−0.18%) |
| `macos-latest` | 23.259s ± 1.206s | 25.076s ± 2.279s | +1.817s (+7.8%)
|
| `windows-latest` | 29.828s ± 1.651s | 30.329s ± 2.428s | +0.501s
(+1.7%) |
Workflow run: https://github.com/dscho/git/actions/runs/25374127848
## Results: 4x larger `linux v3.0` workload (255,039 commits, 2,059,429
objects, ~788 MB pack)
| Platform | vanilla mean ± stdev | mimalloc mean ± stdev | Δ (mimalloc
− vanilla) |
|---|---|---|---|
| `ubuntu-latest` | 134.723s ± **0.329s** | 134.801s ± **0.191s** |
+0.078s (+0.06%) |
| `macos-latest` | 130.183s ± 19.098s | 133.292s ± 18.991s | +3.109s
(+2.4%) |
| `windows-latest` | 145.183s ± 1.272s | 146.271s ± 4.161s | +1.088s
(+0.75%) |
Workflow run: https://github.com/dscho/git/actions/runs/25376885309
## Discussion
The Linux numbers on the larger workload are particularly clear: stdev
is below 0.3% of the mean for both variants, and the difference is well
inside that floor. Glibc's allocator and the vendored mimalloc are
statistically indistinguishable for `git repack -adfq` here.
`windows-latest` runners are noisier (per-run variance ~1-4%, mostly
neighbour-VM scheduling), but mimalloc never beats vanilla in either
workload. With the original justification for keeping a custom allocator
gone (the modern Windows segment-heap is no longer the slow
Windows-XP-era `HeapAlloc` that drove the original 2009 nedmalloc
adoption), there is nothing left to motivate the maintenance cost of a
vendored allocator.
`macos-latest` is too noisy at n=5 (stdev 14% of the mean) to draw a
firm conclusion, but the visible point-estimate goes the wrong way and
there is no plausible mechanism by which Apple's `libsystem_malloc`
would be slower than mimalloc.
## What this PR does *not* do
It does not by itself remove `nedmalloc` from the tree; that is still
promised as a follow-up of the in-flight upstream patch
https://github.com/gitgitgadget/git/pull/2104, presently in `seen` as
e576abb9f8. The first commit here is an `amend!` whose autosquashed
result is byte-identical to that upstream commit, so once the next
merging-rebase picks up the upstream patch the two will collapse
cleanly.
The five remaining `fixup!` reverts target each of the original
mimalloc-vendoring commits in reverse chronological order; once
autosquashed, the pairs cancel out to empty commits which the rebase
will drop, leaving the tree free of `compat/mimalloc/`, the
`USE_MIMALLOC` build infrastructure, and the supporting changes
(`compat/posix.h` `_DEFAULT_SOURCE` guard, `win32_pthread_*` renames)
that only existed to support the vendored allocator.
Part of the series that drops the vendored `mimalloc` from this fork;
the rationale (no measurable speedup over the platform allocator on
any of Windows, macOS, or Linux) is in the second commit of the
series and the PR description. The original commit was a preparation
step for vendoring `mimalloc` in (which forces C11 mode under
mingw-w64 GCC and so implicitly links libwinpthread, clashing with
Git's own emulation). With `mimalloc` gone the rename is no longer
needed, so this revert restores the plain `pthread_create` /
`pthread_self` names. The `fixup!` subject is so the next rebase
against an upstream Git that already lacks the target commit
autosquashes this revert into it, dropping the original cleanly.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Part of the series that drops the vendored `mimalloc` from this fork;
the rationale (no measurable speedup over the platform allocator on
any of Windows, macOS, or Linux) is in the second commit of the
series and the PR description. The `fixup!` subject is so the next
rebase against an upstream Git that already lacks the target commit
autosquashes this revert into it, dropping the original cleanly.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Part of the series that drops the vendored `mimalloc` from this fork;
the rationale (no measurable speedup over the platform allocator on
any of Windows, macOS, or Linux) is in the second commit of the
series and the PR description. The `fixup!` subject is so the next
rebase against an upstream Git that already lacks the target commit
autosquashes this revert into it, dropping the original cleanly.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Part of the series that drops the vendored `mimalloc` from this fork;
the rationale (no measurable speedup over the platform allocator on
any of Windows, macOS, or Linux) is in the second commit of the
series and the PR description. The `fixup!` subject is so the next
rebase against an upstream Git that already lacks the target commit
autosquashes this revert into it, dropping the original cleanly.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Re-running the `git repack -adfq` benchmark from
6a29c2dfec ("mingw: use mimalloc",
2019-06-24) against the platform's *current* default allocator (so
without `nedmalloc` in the picture at all) shows mimalloc is no longer
faster than the system allocator on any of Windows, macOS, or Linux,
neither for the original ~30-second `linux v2.6.20` workload nor for a
4x larger `linux v3.0` workload where each individual run takes ~2
minutes (and the noise floor on Linux is below 0.3% of the mean, so
even small differences would be visible if any existed).
`mimalloc` was originally chosen over nedmalloc, not over the system
allocator. Six years on, with nedmalloc now being dropped from the
codebase entirely, the allocator that mimalloc has to beat is whatever
the OS ships by default; modern Windows segment-heap, glibc malloc, and
the macOS libsystem allocator have all closed the gap, and there is no
longer a measurable benefit to keep maintaining a custom allocator.
The actual benchmark methodology, the per-platform numbers, and links
to the workflow runs that produced them are spelled out in the PR
description rather than repeated across each fixup.
The `fixup!` subject is so that the next rebase against an upstream
Git that already lacks this commit will autosquash this revert into
the original (which becomes empty and is dropped), leaving the tree
free of `mimalloc`.
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
mingw: stop using nedmalloc
The vendored nedmalloc allocator under compat/nedmalloc/ has been
unmaintained upstream for a very long time: the original repository at
https://github.com/ned14/nedmalloc received its last commit on July 5,
2014, and was archived (made read-only) by its owner on March 15, 2019.
Our copy has been carried forward unchanged ever since.
The Git for Windows commit that introduced mimalloc as a replacement
on Windows ("mingw: use mimalloc", 2019-06-24, present in the Git for
Windows branch thicket but not upstream) already observed at that time
that nedmalloc had ceased to see any updates for several years.
This came to a head when the Git for Windows SDK upgraded to GCC 16:
the `add_segment()` function in `compat/nedmalloc/malloc.c.h` declares
`int nfences = 0` and only references it inside an `assert()`, which
GCC 16 now flags as `-Wunused-but-set-variable`. Combined with the
`-Werror` enabled by `DEVELOPER=1`, this turns into a hard build
failure:
compat/nedmalloc/malloc.c.h: In function 'add_segment':
compat/nedmalloc/malloc.c.h:3897:7: error: variable 'nfences' set but not used [-Werror=unused-but-set-variable=]
3897 | int nfences = 0;
| ^~~~~~~
cc1.exe: all warnings being treated as errors
The same source built without complaint under GCC 15.2.0; the
regression was bisected to the SDK package update at
https://github.com/git-for-windows/git-sdk-64/commit/188d93dd455
(`mingw-w64-x86_64-gcc 15.2.0-14 -> 16.1.0-1`), with the failing CI
run captured at
https://github.com/git-for-windows/git-sdk-64/actions/runs/25244795074.
Rather than patch the unmaintained vendored sources to silence the
warning, stop opting into nedmalloc altogether on MINGW. The platform
allocator is what every non-MINGW build already uses, and a fresh
build of git.git's master against a minimal Git for Windows SDK
upgraded to GCC 16, with `USE_NED_ALLOCATOR` removed from the MINGW
section, completes successfully.
The compat/nedmalloc/ subtree itself is left in place to keep this
change minimal; nothing in the build links against it any longer, so
it can be removed in a follow-up if desired.
Assisted-by: Claude Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This closes two gaps in the current `AGENTS.md` that came up while
drafting #6231 and #2104:
1. The `Fixup Commits` section only covered `fixup!`. `amend!` has
different semantics (replaces the target's commit message and combines
diffs to produce any final state), and the "amend! whose body is the
upstream commit and whose diff aligns the squashed result with that
upstream commit" pattern is precisely how the first commit of #6231
anticipates the in-flight nedmalloc removal in `seen` as `e576abb9f8`.
That pattern is undocumented today.
2. There is no top-level "Contributing to Git for Windows" section, only
"Contributing to Upstream Git via GitGitGadget". The cross-fork `gh pr
create` invocation, the conditions under which a PR is naturally a
fixup/amend-only series against existing thicket commits, and the
upstream-aligning `amend!` shape were all things I inferred from context
rather than the guide.
Add subsections that cover those gaps. Nothing in the existing text
changes.
When checkout.workers > 1 and core.fscache is enabled on Windows,
'git checkout <tree> -- <pathspec>' fails when restoring files into
directories that do not yet exist on disk. Two failure modes occur:
1. create_directories(): the fscache returns a stale directory listing
that does not include a just-created directory. has_dirs_only_path()
reports it as non-existent, triggering the unlink+mkdir recovery
path which fails with 'cannot create directory: Directory not empty'.
2. write_pc_item(): after writing and closing a file, lstat() cannot
see it through the stale fscache, failing with 'unable to stat
just-written file'.
With workers=1, write_entry() calls flush_fscache() after each file,
keeping the cache in sync. With workers>1, enqueue_checkout() defers
the write (and the flush), leaving the cache stale for subsequent
entries.
Fix both by adding flush_fscache() calls after mkdir() in
create_directories() and before lstat() in write_pc_item(). On
non-Windows platforms flush_fscache() is a no-op.
Assisted-by: Claude Opus 4.6
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
build: tolerate use of _Generic from glibc 2.43 with Clang
When building with `make DEVELOPER=1` we explicitly pass "-std=gnu99" to
the compiler so that we don't start leaning on features exposed by more
recent versions of the C standard. Unfortunately though, glibc 2.43
started to use type-generic expressions. This works alright with GCC,
but when compiling with Clang this leads to errors:
$ make DEVELOPER=1 CC=clang
CC daemon.o
In file included from daemon.c:3:
./git-compat-util.h:344:11: error: '_Generic' is a C11 extension [-Werror,-Wc11-extensions]
344 | return !!strchr(path, '/');
| ^
/usr/include/string.h:265:3: note: expanded from macro 'strchr'
265 | __glibc_const_generic (S, const char *, strchr (S, C))
| ^
/usr/include/x86_64-linux-gnu/sys/cdefs.h:838:3: note: expanded from macro '__glibc_const_generic'
838 | _Generic (0 ? (PTR) : (void *) 1, \
| ^
In theory, the `__glibc_const_generic` macro does have feature gating:
#if !defined __cplusplus \
&& (__GNUC_PREREQ (4, 9) \
|| __glibc_has_extension (c_generic_selections) \
|| (!defined __GNUC__ && defined __STDC_VERSION__ \
&& __STDC_VERSION__ >= 201112L))
# define __HAVE_GENERIC_SELECTION 1
#else
# define __HAVE_GENERIC_SELECTION 0
#endif
But this feature gating isn't effective because `_has_extension()` will
always evaluate to true as C generics _are_ available as a language
extension to GNU C99 when using Clang. This would have been different if
`_has_feature()` was used instead, in which case it would have properly
evaluated to `false`.
GCC has a workaround to squelch this warning from standard system
headers, but because clang fails due to [-Werror,-Wc11-extensions],
as it lacks the corresponding workaround.
For both meson and Makefile, pass -Wno-c11-extensions when we are
building with clang.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Helped-by: Shardul Natu <snatu@google.com>
[jc: replaced Makefile side with Shardul's approach]
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The `linux-{asan-ubsan,sha256,reftable}` jobs run inside
`ubuntu:rolling`, which now resolves to Ubuntu 26.04 with glibc 2.43;
that pulls `_Generic` into `<sys/cdefs.h>` and breaks our `-std=gnu99
-Werror` Clang builds. Concrete failure:
https://github.com/git-for-windows/git/actions/runs/25390480083/job/74463338845.
Picking up Patrick Steinhardt's fix from
https://lore.kernel.org/git/20260505-b4-pks-ci-tolerate-glibc-generic-v1-1-5786386fe512@pks.im/
ahead of its upstream merge so the GfW CI goes green again. The diff
conflicts with `fe5704a3695c "mimalloc: offer a build-time option to
enable it"`, which wraps the affected `config.mak.dev` block in `ifndef
USE_MIMALLOC`; the resolution preserves that wrap on the `gcc6`-only
branch surviving Patrick's patch. `meson.build` auto-merged.
When building with `make DEVELOPER=1` we explicitly pass "-std=gnu99" to
the compiler so that we don't start leaning on features exposed by more
recent versions of the C standard. Unfortunately though, glibc 2.43
started to use type-generic expressions. This works alright with GCC,
but when compiling with Clang this leads to errors:
$ make DEVELOPER=1 CC=clang
CC daemon.o
In file included from daemon.c:3:
./git-compat-util.h:344:11: error: '_Generic' is a C11 extension [-Werror,-Wc11-extensions]
344 | return !!strchr(path, '/');
| ^
/usr/include/string.h:265:3: note: expanded from macro 'strchr'
265 | __glibc_const_generic (S, const char *, strchr (S, C))
| ^
/usr/include/x86_64-linux-gnu/sys/cdefs.h:838:3: note: expanded from macro '__glibc_const_generic'
838 | _Generic (0 ? (PTR) : (void *) 1, \
| ^
In theory, the `__glibc_const_generic` macro does have feature gating:
#if !defined __cplusplus \
&& (__GNUC_PREREQ (4, 9) \
|| __glibc_has_extension (c_generic_selections) \
|| (!defined __GNUC__ && defined __STDC_VERSION__ \
&& __STDC_VERSION__ >= 201112L))
# define __HAVE_GENERIC_SELECTION 1
#else
# define __HAVE_GENERIC_SELECTION 0
#endif
But this feature gating isn't effective because `_has_extension()` will
always evaluate to true as C generics _are_ available as a language
extension to GNU C99 when using Clang. This would have been different if
`_has_feature()` was used instead, in which case it would have properly
evaluated to `false`.
Unfortunately, there is no easy way for us to work around the warning.
We cannot define `__HAVE_GENERIC_SELECTION` ourselves as that would lead
to a redefinition, and given that the conditions are or'd together we
cannot disable any of those, either.
Instead, work around the issue by not using -std=gnu99 with Clang when
using the Makefile and by disabling warnings about C11 extensions when
using Meson. This isn't ideal, but we at least retain the ability to
detect the (mis-)use of features from newer standards with GCC.
An alternative to this might be to simply bump the required C standard
to C11, which is 15 years old by now and should have support on most
platforms out there. But some more esoteric platforms may not have it.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The existing `Fixup Commits` section explained the `fixup!` flavour
but said nothing about `amend!`, which has different semantics
(replaces the target's commit message and combines diffs to produce
any desired final state). The `amend!` form is also the canonical
way to align a downstream branch-thicket commit with an in-flight
upstream replacement, so its absence from the guide left a hole that
contributors fill by reading the merging-rebase machinery from
source.
Add a dedicated subsection covering `amend!`, plus a separate
subsection on the pattern of constructing PRs that consist *only* of
`fixup!` and `amend!` commits targeting existing thicket commits.
That pattern is the natural shape for a PR that adjusts or removes a
multi-commit downstream feature: each pair autosquashes during the
next merging-rebase, exact-cancel pairs drop as empty, and the end
state is as if the originals had been edited or removed in place.
Also add a top-level `Contributing to Git for Windows` section to
parallel the existing `Contributing to Upstream Git via GitGitGadget`
section, with the cross-fork `gh pr create` invocation, a pointer to
when the fixup-and-amend-only shape is appropriate, and a pointer to
when the upstream-aligning `amend!` pattern is appropriate. Until
now the guide covered upstream contributions in detail but said
nothing about the primary contribution path for this fork.
Assisted-by: Claude Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>