Commit Graph

1197 Commits

Author SHA1 Message Date
Ben Peart
8202d91d79 fscache: add fscache hit statistics
Track fscache hits and misses for lstat and opendir requests.  Reporting of
statistics is done when the cache is disabled for the last time and freed
and is only reported if GIT_TRACE_FSCACHE is set.

Sample output is:

11:33:11.836428 compat/win32/fscache.c:433 fscache: lstat 3775, opendir 263, total requests/misses 4052/269

Signed-off-by: Ben Peart <benpeart@microsoft.com>
2025-06-11 08:25:45 +02:00
Ben Peart
0404729430 fscache: add GIT_TEST_FSCACHE support
Add support to fscache to enable running the entire test suite with the
fscache enabled.

Signed-off-by: Ben Peart <benpeart@microsoft.com>
2025-06-11 08:25:45 +02:00
Ben Peart
96870d1b25 fscache: use FindFirstFileExW to avoid retrieving the short name
Use FindFirstFileExW with FindExInfoBasic to avoid forcing NTFS to look up
the short name.  Also switch to a larger (64K vs 4K) buffer using
FIND_FIRST_EX_LARGE_FETCH to minimize round trips to the kernel.

In a repo with ~200K files, this drops warm cache status times from 3.19
seconds to 2.67 seconds for a 16% savings.

Signed-off-by: Ben Peart <benpeart@microsoft.com>
2025-06-11 08:25:45 +02:00
Takuto Ikuta
bbc8a771d1 checkout.c: enable fscache for checkout again
This is retry of #1419.

I added flush_fscache macro to flush cached stats after disk writing
with tests for regression reported in #1438 and #1442.

git checkout checks each file path in sorted order, so cache flushing does not
make performance worse unless we have large number of modified files in
a directory containing many files.

Using chromium repository, I tested `git checkout .` performance when I
delete 10 files in different directories.
With this patch:
TotalSeconds: 4.307272
TotalSeconds: 4.4863595
TotalSeconds: 4.2975562
Avg: 4.36372923333333

Without this patch:
TotalSeconds: 20.9705431
TotalSeconds: 22.4867685
TotalSeconds: 18.8968292
Avg: 20.7847136

I confirmed this patch passed all tests in t/ with core_fscache=1.

Signed-off-by: Takuto Ikuta <tikuta@chromium.org>
2025-06-11 08:25:44 +02:00
Jeff Hostetler
382c1cae57 fscache: make fscache_enabled() public
Make fscache_enabled() function public rather than static.
Remove unneeded fscache_is_enabled() function.
Change is_fscache_enabled() macro to call fscache_enabled().

is_fscache_enabled() now takes a pathname so that the answer
is more precise and mean "is fscache enabled for this pathname",
since fscache only stores repo-relative paths and not absolute
paths, we can avoid attempting lookups for absolute paths.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
2025-06-11 08:25:44 +02:00
Jeff Hostetler
1b7d89aa1f dir.c: make add_excludes aware of fscache during status
Teach read_directory_recursive() and add_excludes() to
be aware of optional fscache and avoid trying to open()
and fstat() non-existant ".gitignore" files in every
directory in the worktree.

The current code in add_excludes() calls open() and then
fstat() for a ".gitignore" file in each directory present
in the worktree.  Change that when fscache is enabled to
call lstat() first and if present, call open().

This seems backwards because both lstat needs to do more
work than fstat.  But when fscache is enabled, fscache will
already know if the .gitignore file exists and can completely
avoid the IO calls.  This works because of the lstat diversion
to mingw_lstat when fscache is enabled.

This reduced status times on a 350K file enlistment of the
Windows repo on a NVMe SSD by 0.25 seconds.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
2025-06-11 08:25:44 +02:00
Jeff Hostetler
25891d57d6 fscache: remember not-found directories
Teach FSCACHE to remember "not found" directories.

This is a performance optimization.

FSCACHE is a performance optimization available for Windows.  It
intercepts Posix-style lstat() calls into an in-memory directory
using FindFirst/FindNext.  It improves performance on Windows by
catching the first lstat() call in a directory, using FindFirst/
FindNext to read the list of files (and attribute data) for the
entire directory into the cache, and short-cut subsequent lstat()
calls in the same directory.  This gives a major performance
boost on Windows.

However, it does not remember "not found" directories.  When STATUS
runs and there are missing directories, the lstat() interception
fails to find the parent directory and simply return ENOENT for the
file -- it does not remember that the FindFirst on the directory
failed. Thus subsequent lstat() calls in the same directory, each
re-attempt the FindFirst.  This completely defeats any performance
gains.

This can be seen by doing a sparse-checkout on a large repo and
then doing a read-tree to reset the skip-worktree bits and then
running status.

This change reduced status times for my very large repo by 60%.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:25:44 +02:00
Jeff Hostetler
666f0f36db fscache: add key for GIT_TRACE_FSCACHE
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:25:44 +02:00
Karsten Blees
43199376c0 fscache: load directories only once
If multiple threads access a directory that is not yet in the cache, the
directory will be loaded by each thread. Only one of the results is added
to the cache, all others are leaked. This wastes performance and memory.

On cache miss, add a future object to the cache to indicate that the
directory is currently being loaded. Subsequent threads register themselves
with the future object and wait. When the first thread has loaded the
directory, it replaces the future object with the result and notifies
waiting threads.

Signed-off-by: Karsten Blees <blees@dcon.de>
2025-06-11 08:25:44 +02:00
Karsten Blees
1238254c52 mingw: add a cache below mingw's lstat and dirent implementations
Checking the work tree status is quite slow on Windows, due to slow
`lstat()` emulation (git calls `lstat()` once for each file in the
index). Windows operating system APIs seem to be much better at scanning
the status of entire directories than checking single files.

Add an `lstat()` implementation that uses a cache for lstat data. Cache
misses read the entire parent directory and add it to the cache.
Subsequent `lstat()` calls for the same directory are served directly
from the cache.

Also implement `opendir()`/`readdir()`/`closedir()` so that they create
and use directory listings in the cache.

The cache doesn't track file system changes and doesn't plug into any
modifying file APIs, so it has to be explicitly enabled for git functions
that don't modify the working copy.

Note: in an earlier version of this patch, the cache was always active and
tracked file system changes via ReadDirectoryChangesW. However, this was
much more complex and had negative impact on the performance of modifying
git commands such as 'git checkout'.

Signed-off-by: Karsten Blees <blees@dcon.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:25:44 +02:00
Karsten Blees
63df1b22f5 mingw: add infrastructure for read-only file system level caches
Add a macro to mark code sections that only read from the file system,
along with a config option and documentation.

This facilitates implementation of relatively simple file system level
caches without the need to synchronize with the file system.

Enable read-only sections for 'git status' and preload_index.

Signed-off-by: Karsten Blees <blees@dcon.de>
2025-06-11 08:25:44 +02:00
Karsten Blees
d1f5e7c1f3 Win32: make the lstat implementation pluggable
Emulating the POSIX lstat API on Windows via GetFileAttributes[Ex] is quite
slow. Windows operating system APIs seem to be much better at scanning the
status of entire directories than checking single files. A caching
implementation may improve performance by bulk-reading entire directories
or reusing data obtained via opendir / readdir.

Make the lstat implementation pluggable so that it can be switched at
runtime, e.g. based on a config option.

Signed-off-by: Karsten Blees <blees@dcon.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:25:43 +02:00
Karsten Blees
9451c6b76b mingw: make the dirent implementation pluggable
Emulating the POSIX `dirent` API on Windows via
`FindFirstFile()`/`FindNextFile()` is pretty staightforward, however,
most of the information provided in the `WIN32_FIND_DATA` structure is
thrown away in the process. A more sophisticated implementation may
cache this data, e.g. for later reuse in calls to `lstat()`.

Make the `dirent` implementation pluggable so that it can be switched at
runtime, e.g. based on a config option.

Define a base DIR structure with pointers to `readdir()`/`closedir()`
that match the `opendir()` implementation (similar to vtable pointers in
Object-Oriented Programming). Define `readdir()`/`closedir()` so that
they call the function pointers in the `DIR` structure. This allows to
choose the `opendir()` implementation on a call-by-call basis.

Make the fixed-size `dirent.d_name` buffer a flex array, as `d_name` may
be implementation specific (e.g. a caching implementation may allocate a
`struct dirent` with _just_ the size needed to hold the `d_name` in
question).

Signed-off-by: Karsten Blees <blees@dcon.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:25:43 +02:00
Karsten Blees
4e349eb83f Win32: dirent.c: Move opendir down
Move opendir down in preparation for the next patch.

Signed-off-by: Karsten Blees <blees@dcon.de>
2025-06-11 08:25:43 +02:00
Karsten Blees
5f44a60db4 Win32: make FILETIME conversion functions public
We will use them in the upcoming "FSCache" patches (to accelerate
sequential lstat() calls).

Signed-off-by: Karsten Blees <blees@dcon.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:25:43 +02:00
Johannes Schindelin
cca45ceb8a mingw: avoid the comma operator (#5660)
The pattern `return errno = ..., -1;` is observed several times in
`compat/mingw.c`. It has served us well over the years, but now clang
starts complaining:

```
  compat/mingw.c:723:24: error: possible misuse of comma operator here [-Werror,-Wcomma]
    723 |                 return errno = ENOSYS, -1;
        |                                      ^
```

See for example [this failing workflow
run](https://github.com/git-for-windows/git-sdk-arm64/actions/runs/15457893907/job/43513458823#step:8:201).

Let's appease clang (and also reduce the use of the no longer common
comma operator).
2025-06-11 08:25:28 +02:00
Johannes Schindelin
762bcee13f mingw: avoid the comma operator
The pattern `return errno = ..., -1;` is observed several times in
`compat/mingw.c`. It has served us well over the years, but now clang
starts complaining:

  compat/mingw.c:723:24: error: possible misuse of comma operator here [-Werror,-Wcomma]
    723 |                 return errno = ENOSYS, -1;
        |                                      ^

See for example this failing workflow run:
https://github.com/git-for-windows/git-sdk-arm64/actions/runs/15457893907/job/43513458823#step:8:201

Let's appease clang (and also reduce the use of the no longer common
comma operator).

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:22:54 +02:00
Johannes Schindelin
49d26649d4 mingw_rename: support ReFS on Windows 2022 (#5515)
Git on Windows 2022 fails to write config files on ReFS with the error
message "Function not implemented". The reason is that
`ERROR_NOT_SUPPORTED` is reported (not `ERROR_INVALID_PARAMETER`, as
expected). Let's handle both errors the same: by falling back to the
best-effort option, namely to rename without POSIX semantics.

This fixes https://github.com/git-for-windows/git/issues/5427
2025-06-11 08:16:47 +02:00
Johannes Schindelin
e810ee5f8f Drop support for core.restrictInheritedHandles, as it targeted Windows 7 and earlier (#5460)
There has been a slow but steady stream of bug reports triggered by the
warning included in ac33519ddf. Since
introducing the escape hatch for Windows 7 in that same patch, however,
I have not seen a single report that pointed to the kind of bug I
anticipated when writing that warning message.

Let's drop this warning, as well as the escape hatch: Git for Windows
dropped supporting Windows 7 (and Windows 8) directly after Git for
Windows v2.46.2. For full details, see
https://gitforwindows.org/requirements#windows-version.

For good measure, let's keep the fall-back, though: It sometimes helps
work around issues (e.g. when Defender still holds a handle on a file
that Git wants to write out).
2025-06-11 08:16:47 +02:00
Johannes Schindelin
c19467a188 mingw_open_existing: handle directories better (#5342)
[`CreateFileW()` requires `FILE_FLAG_BACKUP_SEMANTICS` to create a
directory
handle](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#directories)
and errors out with `ERROR_ACCESS_DENIED` without this flag. Fall back
to accessing Directory handles this way.

This fixes https://github.com/git-for-windows/git/issues/5068
2025-06-11 08:16:47 +02:00
Johannes Schindelin
ed886133e6 credential-cache: handle ECONNREFUSED gracefully (#5329)
I should probably add some tests for this.
2025-06-11 08:16:47 +02:00
Johannes Schindelin
3de18de3fc Merge branch 'run-command-be-helpful-when-Git-LFS-fails-on-Windows-7'
Since Git LFS v3.5.x implicitly dropped Windows 7 support, we now want
users to be advised _what_ is going wrong on that Windows version. This
topic branch goes out of its way to provide users with such guidance.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:16:46 +02:00
Johannes Schindelin
04c2e00513 Merge branch 'Fix-i686-build-with-GCC-v14'
This fixes a long-time compile warning turned error by GCC v14.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:16:45 +02:00
Johannes Schindelin
ecca848c69 win32: use native ANSI sequence processing, if possible (#4700)
Windows 10 version 1511 (also known as Anniversary Update), according to
https://learn.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences
introduced native support for ANSI sequence processing. This allows
using colors from the entire 24-bit color range.

All we need to do is test whether the console's "virtual processing
support" can be enabled. If it can, we do not even need to start the
`console_thread` to handle ANSI sequences.

Incidentally, this addresses
https://github.com/git-for-windows/git/issues/3712.
2025-06-11 08:16:45 +02:00
Johannes Schindelin
a813fe394a Additional error checks for issuing the windows.appendAtomically warning (#4528)
Another (hopefully clean) PR for showing the error warning about atomic
append on windows after failure on APFS, which returns EBADF not EINVAL.

Signed-off-by: David Lomas <dl3@pale-eds.co.uk>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
2025-06-11 08:16:44 +02:00
Johannes Schindelin
7c3a2a15d1 Lazy load libcurl, allowing for an SSL/TLS backend-specific libcurl (#4410)
As per
https://github.com/git-for-windows/git/issues/4350#issuecomment-1485041503,
the major block for upgrading Git for Windows' OpenSSL from v1.1 to v3
is the tricky part where such an upgrade would break `git fetch`/`git
clone` and `git push` because the libcurl depends on the OpenSSL DLL,
and the major version bump will _change_ the file name of said DLL.

To overcome that, the plan is to build libcurl flavors for each
supported SSL/TLS backend, aligning with the way MSYS2 builds libcurl,
then switch Git for Windows' SDK to the Secure Channel-flavored libcurl,
and teach Git to look for the specific flavor of libcurl corresponding
to the `http.sslBackend` setting (if that was configured).

Here is the PR to teach Git that trick.
2025-06-11 08:16:44 +02:00
Johannes Schindelin
f3db6f95d2 Merge branch 'fsync-object-files-always'
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:16:43 +02:00
Johannes Schindelin
5502ea8b19 Merge branch 'optionally-dont-append-atomically-on-windows'
Fix append failure issue under remote directories #2753

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:16:43 +02:00
Johannes Schindelin
2fa87ea8b3 Merge pull request #3875 from 1480c1/wine/detect_msys_tty
winansi: check result before using Name for pty
2025-06-11 08:16:42 +02:00
Johannes Schindelin
7ed51cebf6 Merge pull request #3751 from rkitover/native-term
mingw: set $env:TERM=xterm-256color for newer OSes
2025-06-11 08:16:42 +02:00
Derrick Stolee
9f5a298d75 Merge pull request #3791: Various fixes around safe.directory
The first three commits are rebased versions of those in gitgitgadget/git#1215. These allow the following:

1. Fix `git config --global foo.bar <path>` from allowing the `<path>`. As a bonus, users with a config value starting with `/` will not get a warning about "old-style" paths needing a "`%(prefix)/`".

2. When in WSL, the path starts with `/` so it needs to be interpolated properly. Update the warning to include `%(prefix)/` to get the right value for WSL users. (This is specifically for using Git for Windows from Git Bash, but in a WSL directory.)

3. When using WSL, the ownership check fails and reports an error message. This is noisy, and happens even if the user has marked the path with `safe.directory`. Remove that error message.
2025-06-11 08:16:42 +02:00
Johannes Schindelin
52238c9610 Merge pull request #3220 from dscho/there-is-no-vs/master-anymore
Let the documentation reflect that there is no vs/master anymore
2025-06-11 08:16:41 +02:00
Johannes Schindelin
c3d72322d6 Merge pull request #3165 from dscho/increase-allowed-length-of-interpreter-path
mingw: allow for longer paths in `parse_interpreter()`
2025-06-11 08:16:41 +02:00
Johannes Schindelin
b07e698ac1 Merge pull request #2915 from dennisameling/windows-arm64-support
Windows arm64 support
2025-06-11 08:16:40 +02:00
Johannes Schindelin
43ebf53ea8 Merge pull request #2351 from PhilipOakley/vcpkg-tip
Vcpkg Install: detect lack of working Git, and note possible vcpkg time outs
2025-06-11 08:16:40 +02:00
Johannes Schindelin
9525088239 Merge pull request #2974 from derrickstolee/maintenance-and-headless
Include Windows-specific maintenance and headless-git
2025-06-11 08:16:39 +02:00
Johannes Schindelin
cb81d55e9c Merge pull request #2506 from dscho/issue-2283
Allow running Git directly from `C:\Program Files\Git\mingw64\bin\git.exe`
2025-06-11 08:16:38 +02:00
Johannes Schindelin
e10220f2f9 Merge pull request #2504 from dscho/access-repo-via-junction
Handle `git add <file>` where <file> traverses an NTFS junction
2025-06-11 08:16:38 +02:00
Johannes Schindelin
50c4da7948 Merge pull request #2501 from jeffhostetler/clink-debug-curl
clink.pl: fix MSVC compile script to handle libcurl-d.lib
2025-06-11 08:16:37 +02:00
Johannes Schindelin
137b05ba61 Merge pull request #2488 from bmueller84/master
mingw: fix fatal error working on mapped network drives on Windows
2025-06-11 08:16:37 +02:00
Johannes Schindelin
856ea732fd Merge pull request #2449 from dscho/mingw-getcwd-and-symlinks
Do resolve symlinks in `getcwd()`
2025-06-11 08:16:37 +02:00
Johannes Schindelin
98e9e60290 Merge branch 'mimalloc-v2.2.3'
This topic vendors in mimalloc v2.2.3, a fast allocator that allows Git
for Windows to perform efficiently.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:16:37 +02:00
Johannes Schindelin
828d60d89b Merge branch 'dont-clean-junctions'
This topic branch teaches `git clean` to respect NTFS junctions and Unix
bind mounts: it will now stop at those boundaries.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:16:36 +02:00
Johannes Schindelin
dcf54ff703 Merge branch 'drive-prefix'
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>
2025-06-11 08:16:36 +02:00
Johannes Schindelin
22f42a080a mingw_rename: support ReFS on Windows 2022
ReFS is an alternative filesystem to NTFS. On Windows 2022, it seems not
to support the rename operation using POSIX semantics that Git uses on
Windows as of 391bceae43 (compat/mingw: support POSIX semantics for
atomic renames, 2024-10-27).

However, Windows 2022 reports `ERROR_NOT_SUPPORTED` in this instance.
This is in contrast to `ERROR_INVALID_PARAMETER` (as previous Windows
versions would report that do not support POSIX semantics in renames at
all).

Let's handle both errors the same: by falling back to the best-effort
option, namely to rename without POSIX semantics.

This fixes https://github.com/git-for-windows/git/issues/5427

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:16:35 +02:00
Johannes Schindelin
9db3a65448 mingw: drop Windows 7-specific work-around
In ac33519ddf (mingw: restrict file handle inheritance only on Windows
7 and later, 2019-11-22), I introduced code to safe-guard the
defense-in-depth handling that restricts handles' inheritance so that it
would work with Windows 7, too.

Let's revert this patch: Git for Windows dropped supporting Windows 7 (and
Windows 8) directly after Git for Windows v2.46.2. For full details, see
https://gitforwindows.org/requirements#windows-version.

Actually, on second thought: revert only the part that makes this handle
inheritance restriction logic optional and that suggests to open a bug
report if it fails, but keep the fall-back to try again without said
logic: There have been a few false positives over the past few years
(where the warning was triggered e.g. because Defender was still
accessing a file that Git wanted to overwrite), and the fall-back logic
seems to have helped occasionally in such situations.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:16:35 +02:00
Matthias Aßhauer
e5585c49fa mingw_open_existing: handle directories better
CreateFileW() requires FILE_FLAG_BACKUP_SEMANTICS to create a directory
handle [1] and errors out with ERROR_ACCESS_DENIED without this flag.
Fall back to accessing Directory handles this way.

[1] https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew#directories

This fixes https://github.com/git-for-windows/git/issues/5068

Signed-off-by: Matthias Aßhauer <mha1993@live.de>
2025-06-11 08:16:35 +02:00
Matthias Aßhauer
5ec808bbaa compat/mingw: drop outdated comment
This comment has been true for the longest time; The combination of the
two preceding commits made it incorrect, so let's drop that comment.

Signed-off-by: Matthias Aßhauer <mha1993@live.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:16:35 +02:00
Matthias Aßhauer
0a19fc6bf1 compat/mingw: handle WSA errors in strerror
We map WSAGetLastError() errors to errno errors in winsock_error_to_errno(),
but the MSVC strerror() implementation only produces "Unknown error" for
most of them. Produce some more meaningful error messages in these
cases.

Our builds for ARM64 link against the newer UCRT strerror() that does know
these errors, so we won't change the strerror() used there.

The wording of the messages is copied from glibc strerror() messages.

Reported-by: M Hickford <mirth.hickford@gmail.com>
Signed-off-by: Matthias Aßhauer <mha1993@live.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:16:35 +02:00
Johannes Schindelin
a9fac0d314 mingw: make sure errno is set correctly when socket operations fail
The winsock2 library provides functions that work on different data
types than file descriptors, therefore we wrap them.

But that is not the only difference: they also do not set `errno` but
expect the callers to enquire about errors via `WSAGetLastError()`.

Let's translate that into appropriate `errno` values whenever the socket
operations fail so that Git's code base does not have to change its
expectations.

This closes https://github.com/git-for-windows/git/issues/2404

Helped-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2025-06-11 08:16:34 +02:00