79519 Commits

Author SHA1 Message Date
Junio C Hamano
c3e53d2070 Merge branch 'jk/cat-file-avoid-bitmap-when-unneeded' into jch
Fix for a performance regression in "git cat-file".

* jk/cat-file-avoid-bitmap-when-unneeded:
  cat-file: only use bitmaps when filtering
2026-01-10 19:40:31 -08:00
Junio C Hamano
900bd06ad7 Merge branch 'jk/t-perf-fixes' into jch
Perf-test fixes.

* jk/t-perf-fixes:
  t/perf/run: preserve GIT_PERF_* from environment
  t/perf/perf-lib: fix assignment of TEST_OUTPUT_DIRECTORY
2026-01-10 19:40:31 -08:00
Junio C Hamano
7d26c55435 Merge branch 'ps/read-object-info-improvements' into jch
The object-info API has been cleaned up.

Comments?

* ps/read-object-info-improvements:
  packfile: drop repository parameter from `packed_object_info()`
  packfile: skip unpacking object header for disk size requests
  packfile: disentangle return value of `packed_object_info()`
  packfile: always populate pack-specific info when reading object info
  packfile: extend `is_delta` field to allow for "unknown" state
  packfile: always declare object info to be OI_PACKED
  object-file: always set OI_LOOSE when reading object info
2026-01-10 19:40:31 -08:00
Junio C Hamano
30353e6c79 Merge branch 'en/fsck-snapshot-ref-state' into jch
"git fsck" used inconsistent set of refs to show a confused
warning, which has been corrected.

* en/fsck-snapshot-ref-state:
  fsck: snapshot default refs before object walk
2026-01-10 19:40:30 -08:00
Junio C Hamano
c4e84de8c6 Merge branch 'tt/receive-pack-oo-namespace-symref-fix' into jch
"git receive-pack", when namespace is involved, segfaulted when a
symbolic ref cross the namespace boundary.

Comments?

* tt/receive-pack-oo-namespace-symref-fix:
  receive-pack: fix crash on out-of-namespace symref
2026-01-10 19:40:30 -08:00
Junio C Hamano
1651f7acca Merge branch 'sb/doc-worktree-prune-expire-improvement' into jch
The help text and the documentation for the "--expire" option of
"git worktree [list|prune]" have been improved.

* sb/doc-worktree-prune-expire-improvement:
  worktree: use 'prune' instead of 'expire' in help text
  worktree: clarify --expire applies to missing worktrees
2026-01-10 19:40:30 -08:00
Junio C Hamano
93764017bc Merge branch 'js/symlink-windows' into jch
Upstream symbolic link support on Windows from Git-for-Windows.

* js/symlink-windows:
  mingw: special-case index entries for symlinks with buggy size
  mingw: emulate `stat()` a little more faithfully
  mingw: try to create symlinks without elevated permissions
  mingw: add support for symlinks to directories
  mingw: implement basic `symlink()` functionality (file symlinks only)
  mingw: implement `readlink()`
  mingw: allow `mingw_chdir()` to change to symlink-resolved directories
  mingw: support renaming symlinks
  mingw: handle symlinks to directories in `mingw_unlink()`
  mingw: add symlink-specific error codes
  mingw: change default of `core.symlinks` to false
  mingw: factor out the retry logic
  mingw: compute the correct size for symlinks in `mingw_lstat()`
  mingw: teach dirent about symlinks
  mingw: let `mingw_lstat()` error early upon problems with reparse points
  mingw: drop the separate `do_lstat()` function
  mingw: implement `stat()` with symlink support
  mingw: don't call `GetFileAttributes()` twice in `mingw_lstat()`
2026-01-10 19:40:30 -08:00
Junio C Hamano
890ebd0387 Merge branch 'js/prep-symlink-windows' into jch
Further preparation to upstream symbolic link support on Windows.

* js/prep-symlink-windows:
  trim_last_path_component(): avoid hard-coding the directory separator
  strbuf_readlink(): support link targets that exceed 2*PATH_MAX
  strbuf_readlink(): avoid calling `readlink()` twice in corner-cases
  init: do parse _all_ core.* settings early
  mingw: do resolve symlinks in `getcwd()`
2026-01-10 19:40:30 -08:00
Junio C Hamano
c30ad61184 Merge branch 'ap/http-probe-rpc-use-auth' into jch
* ap/http-probe-rpc-use-auth:
  remote-curl: Use auth for probe_rpc() requests too
2026-01-10 19:40:29 -08:00
Junio C Hamano
a26aeeb51e Merge branch 'sb/doc-update-ref-markup-fix' into jch
Doc mark-up fix.

Will merget to 'next'.

* sb/doc-update-ref-markup-fix:
  doc: fix `update-ref` `symref-create` formatting
2026-01-10 19:40:29 -08:00
Junio C Hamano
bad916fcbe Merge branch 'yc/histogram-hunk-shift-fix' into jch
The final clean-up phase of the diff output could turn the result of
histogram diff algorithm suboptimal, which has been corrected.

Comments?

* yc/histogram-hunk-shift-fix:
  xdiff: re-diff shifted change groups when using histogram algorithm
2026-01-10 19:40:28 -08:00
Junio C Hamano
cf667e12a5 Merge branch 'jk/parse-int' into jch
Introduce a more robust way to parse a decimal integer stored in a
piece of memory that is not necessarily terminated with NUL (which
Asan strict-string-check complains even when use of strtol() is
safe due to varified existence of whitespace after the digits).

* jk/parse-int:
  fsck: use parse_unsigned_from_buf() for parsing timestamp
  cache-tree: use parse_int_from_buf()
  parse: add functions for parsing from non-string buffers
  parse: prefer bool to int for boolean returns
2026-01-10 19:40:28 -08:00
Junio C Hamano
c8fbfc8def Merge branch 'tc/last-modified-options-cleanup' into jch
The "-z" and "--max-depth" documentation (and implementation of
"-z") in the "git last-modified" command have been updated.

* tc/last-modified-options-cleanup:
  fixup! last-modified: document option --max-depth
  last-modified: document how depth is handled better
  last-modified: document option --max-depth
  last-modified: handle and document NUL termination
2026-01-10 19:40:28 -08:00
Junio C Hamano
066b3e6699 Merge branch 'kn/ref-location' into jch
A mechanism to specify what reference backend to use and store
references in which directory is introduced, which would likely to
be useful during ref migration.

Comments?

* kn/ref-location:
  refs: add GIT_REF_URI to specify reference backend and directory
  refs: support obtaining ref_store for given dir
2026-01-10 19:40:28 -08:00
Junio C Hamano
fb0bf6ab2f Merge branch 'wm/complete-git-short-opts' into jch
The command line completion script (in contrib/) learned to
complete "git -<TAB>" to give single-letter options like "-C".

* wm/complete-git-short-opts:
  completion: complete "git -<TAB>" with short options
2026-01-10 19:40:27 -08:00
Junio C Hamano
abb4891edb Merge branch 'ar/submodule-gitdir-tweak' into jch
Avoid local submodule repository directory paths overlapping with
each other by encoding submodule names before using them as path
components.

Comments?

* ar/submodule-gitdir-tweak:
  submodule: detect conflicts with existing gitdir configs
  submodule: hash the submodule name for the gitdir path
  submodule: fix case-folding gitdir filesystem collisions
  submodule--helper: fix filesystem collisions by encoding gitdir paths
  builtin/credential-store: move is_rfc3986_unreserved to url.[ch]
  submodule--helper: add gitdir migration command
  submodule: allow runtime enabling extensions.submodulePathConfig
  submodule: introduce extensions.submodulePathConfig
  builtin/submodule--helper: add gitdir command
  submodule: always validate gitdirs inside submodule_name_to_gitdir
  submodule--helper: use submodule_name_to_gitdir in add_submodule
2026-01-10 19:40:27 -08:00
Junio C Hamano
6d16983b69 Merge branch 'ps/packfile-store-in-odb-source' into jch
The packfile_store data structure is moved from object store to odb
source.

* ps/packfile-store-in-odb-source:
  packfile: move MIDX into packfile store
  packfile: refactor `find_pack_entry()` to work on the packfile store
  packfile: inline `find_kept_pack_entry()`
  packfile: only prepare owning store in `packfile_store_prepare()`
  packfile: only prepare owning store in `packfile_store_get_packs()`
  packfile: move packfile store into object source
  packfile: refactor misleading code when unusing pack windows
  packfile: refactor kept-pack cache to work with packfile stores
  packfile: pass source to `prepare_pack()`
  packfile: create store via its owning source
2026-01-10 19:40:27 -08:00
Junio C Hamano
5a1415efa7 Merge branch 'js/mailmap-karsten-blees' into jch
* js/mailmap-karsten-blees:
  .mailmap: replace Karsten Blees' default address
2026-01-10 19:40:21 -08:00
Johannes Schindelin
e97678c4ef .mailmap: replace Karsten Blees' default address
As per a recent email by Karsten, the @dcon.de address no longer works:
https://lore.kernel.org/git/77e768b2-6693-454f-9e11-fb0acdec703c@gmail.com

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-10 09:32:51 -08:00
Junio C Hamano
be3a5fd9e0 ### match next 2026-01-09 18:37:07 -08:00
Junio C Hamano
9ee9d92979 Merge branch 'ps/clar-integers' into jch
Import newer version of "clar", unit testing framework.

* ps/clar-integers:
  gitattributes: disable blank-at-eof errors for clar test expectations
  t/unit-tests: demonstrate use of integer comparison assertions
  t/unit-tests: update clar to 39f11fe
2026-01-09 18:37:07 -08:00
Junio C Hamano
df4ff54ed8 Merge branch 'kh/replay-invalid-onto-advance' into jch
Improve the error message when a bad argument is given to the
`--onto` option of "git replay".  Test coverage of "git replay" has
been improved.

* kh/replay-invalid-onto-advance:
  t3650: add more regression tests for failure conditions
  replay: die if we cannot parse object
  replay: improve code comment and die message
  replay: die descriptively when invalid commit-ish is given
  replay: find *onto only after testing for ref name
  replay: remove dead code and rearrange
2026-01-09 18:37:07 -08:00
Junio C Hamano
f875a8833a Merge branch 'ps/odb-misc-fixes' into jch
Miscellaneous fixes on object database layer.

* ps/odb-misc-fixes:
  odb: properly close sources before freeing them
  builtin/gc: fix condition for whether to write commit graphs
2026-01-09 18:37:07 -08:00
Junio C Hamano
15f521095e Merge branch 'pt/t7800-difftool-test-racefix' into jch
Test fixup.

* pt/t7800-difftool-test-racefix:
  t7800: fix racy "difftool --dir-diff syncs worktree" test
2026-01-09 18:37:06 -08:00
Junio C Hamano
7546d372c3 Merge branch 'ps/t1300-2021-use-test-path-is-helpers' into jch
Test updates.

* ps/t1300-2021-use-test-path-is-helpers:
  t1300: use test helpers instead of `test` command
2026-01-09 18:37:06 -08:00
Junio C Hamano
99a511be73 Merge branch 'rs/commit-stack' into jch
Code clean-up, unifying various hand-rolled "list of commit
objects" and use the commit_stack API.

* rs/commit-stack:
  commit-reach: use commit_stack
  commit-graph: use commit_stack
  commit: add commit_stack_grow()
  shallow: use commit_stack
  pack-bitmap-write: use commit_stack
  commit: add commit_stack_init()
  test-reach: use commit_stack
  remote: use commit_stack for src_commits
  remote: use commit_stack for sent_tips
  remote: use commit_stack for local_commits
  name-rev: use commit_stack
  midx: use commit_stack
  log: use commit_stack
  revision: export commit_stack
2026-01-09 18:37:06 -08:00
Junio C Hamano
b5cc09810a Merge branch 'sb/bundle-uri-without-uri' into jch
Diagnose invalid bundle-URI that lack the URI entry, instead of
crashing.

* sb/bundle-uri-without-uri:
  bundle-uri: validate that bundle entries have a uri
2026-01-09 18:37:06 -08:00
Junio C Hamano
1eab00c410 Merge branch 'ja/doc-synopsis-style-more' into jch
More doc style updates.

* ja/doc-synopsis-style-more:
  doc: convert git-remote to synopsis style
  doc: convert git stage to use synopsis block
  doc: convert git-status tables to AsciiDoc format
  doc: convert git-status to synopsis style
  doc: fix t0450-txt-doc-vs-help to select only first synopsis block
2026-01-09 18:37:06 -08:00
Johannes Schindelin
44af34bde7 mingw: special-case index entries for symlinks with buggy size
In https://github.com/git-for-windows/git/pull/2637, we fixed a bug
where symbolic links' target path sizes were recorded incorrectly in the
index. The downside of this fix was that every user with tracked
symbolic links in their checkouts would see them as modified in `git
status`, but not in `git diff`, and only a `git add <path>` (or `git add
-u`) would "fix" this.

Let's do better than that: we can detect that situation and simply
pretend that a symbolic link with a known bad size (or a size that just
happens to be that bad size, a _very_ unlikely scenario because it would
overflow our buffers due to the trailing NUL byte) means that it needs
to be re-checked as if we had just checked it out.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Johannes Schindelin
2cba5746c0 mingw: emulate stat() a little more faithfully
When creating directories via `safe_create_leading_directories()`, we
might encounter an already-existing directory which is not
readable by the current user. To handle that situation, Git's code calls
`stat()` to determine whether we're looking at a directory.

In such a case, `CreateFile()` will fail, though, no matter what, and
consequently `mingw_stat()` will fail, too. But POSIX semantics seem to
still allow `stat()` to go forward.

So let's call `mingw_lstat()` to the rescue if we fail to get a file
handle due to denied permission in `mingw_stat()`, and fill the stat
info that way.

We need to be careful to not allow this to go forward in case that we're
looking at a symbolic link: to resolve the link, we would still have to
create a file handle, and we just found out that we cannot. Therefore,
`stat()` still needs to fail with `EACCES` in that case.

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

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Johannes Schindelin
6206f7aeb0 mingw: try to create symlinks without elevated permissions
As of Windows 10 Build 14972 in Developer Mode, a new flag is supported
by `CreateSymbolicLink()` to create symbolic links even when running
outside of an elevated session (which was previously required).

This new flag is called `SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE`
and has the numeric value 0x02.

Previous Windows 10 versions will not understand that flag and return
an `ERROR_INVALID_PARAMETER`, therefore we have to be careful to try
passing that flag only when the build number indicates that it is
supported.

For more information about the new flag, see this blog post:
https://blogs.windows.com/buildingapps/2016/12/02/symlinks-windows-10/

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Karsten Blees
97be7aa43a mingw: add support for symlinks to directories
Symlinks on Windows have a flag that indicates whether the target is a
file or a directory. Symlinks of wrong type simply don't work. This even
affects core Win32 APIs (e.g. `DeleteFile()` refuses to delete directory
symlinks).

However, `CreateFile()` with FILE_FLAG_BACKUP_SEMANTICS does work. Check
the target type by first creating a tentative file symlink, opening it,
and checking the type of the resulting handle. If it is a directory,
recreate the symlink with the directory flag set.

It is possible to create symlinks before the target exists (or in case
of symlinks to symlinks: before the target type is known). If this
happens, create a tentative file symlink and postpone the directory
decision: keep a list of phantom symlinks to be processed whenever a new
directory is created in `mingw_mkdir()`.

Limitations: This algorithm may fail if a link target changes from file
to directory or vice versa, or if the target directory is created in
another process. It's the best Git can do, though.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Karsten Blees
593008b95d mingw: implement basic symlink() functionality (file symlinks only)
Implement `symlink()`. This implementation always creates _file_
symlinks (remember: Windows discerns between symlinks pointing to
directories and those pointing to files). Support for directory symlinks
will be added in a subseqeuent commit.

This implementation fails with `ENOSYS` if symlinks are disabled or
unsupported.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Karsten Blees
980852dbff mingw: implement readlink()
Implement `readlink()` by reading NTFS reparse points via the
`read_reparse_point()` function that was introduced earlier to determine
the length of symlink targets. Works for symlinks and directory
junctions.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Karsten Blees
43745a7d55 mingw: allow mingw_chdir() to change to symlink-resolved directories
If symlinks are enabled, resolve all symlinks when changing directories,
as required by POSIX.

Note: Git's `real_path()` function bases its link resolution algorithm
on this property of `chdir()`. Unfortunately, the current directory on
Windows is limited to only MAX_PATH (260) characters. Therefore using
symlinks and long paths in combination may be problematic.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Karsten Blees
5e88e98c04 mingw: support renaming symlinks
Older MSVCRT's `_wrename()` function cannot rename symlinks over
existing files: it returns success without doing anything. Newer
MSVCR*.dll versions probably do not share this problem: according to CRT
sources, they just call `MoveFileEx()` with the `MOVEFILE_COPY_ALLOWED`
flag.

Avoid the `_wrename()` call, and go with directly calling
`MoveFileEx()`, with proper error handling of course.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Karsten Blees
ac41bfa374 mingw: handle symlinks to directories in mingw_unlink()
The `_wunlink()` and `DeleteFileW()` functions refuse to delete symlinks
to directories on Windows; The error code would be `ERROR_ACCESS_DENIED`
in that case. Take that error code as an indicator that we need to try
`_wrmdir()` as well. In the best case, it will remove a symlink. In the
worst case, it will fail with the same error code again.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Karsten Blees
9ac15c2ae3 mingw: add symlink-specific error codes
The Win32 API calls do not set `errno`; Instead, error codes for failed
operations must be obtained via the `GetLastError()` function. Git would
not know what to do with those error values, though, which is why Git's
Windows compatibility layer translates them to `errno` values.

Let's handle a couple of symlink-related error codes that will become
relevant with the upcoming support for symlinks on Windows.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Karsten Blees
1bf1ffadc8 mingw: change default of core.symlinks to false
Symlinks on Windows don't work the same way as on Unix systems. For
example, there are different types of symlinks for directories and
files, and unless using a recent-ish Windows version in Developer Mode,
creating symlinks requires administrative privileges.

By default, disable symlink support on Windows. That is, users
explicitly have to enable it with `git config [--system|--global]
core.symlinks true`; For convenience, `git init` (and `git clone`)
will perform a test whether the current setup allows creating symlinks
and will configure that setting in the repository config.

The test suite ignores system / global config files. Allow
testing *with* symlink support by checking if native symlinks are
enabled in MSYS2 (via setting the special environment variable
`MSYS=winsymlinks:nativestrict` to ask the MSYS2 runtime to enable
creating symlinks).

Note: This assumes that Git's test suite is run in MSYS2's Bash, which
is true for the time being (an experiment to switch to BusyBox-w32
failed due to the experimental nature of BusyBox-w32).

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Karsten Blees
b0b32ff16f mingw: factor out the retry logic
In several places, Git's Windows-specific code follows the pattern where
it tries to perform an operation, and retries several times when that
operation fails, sleeping an increasing amount of time, before finally
giving up and asking the user whether to rety (after, say, closing an
editor that held a handle to a file, preventing the operation from
succeeding).

This logic is a bit hard to use, and inconsistent:
`mingw_unlink()` and `mingw_rmdir()` duplicate the code to retry,
and both of them do so incompletely. They also do not restore `errno` if the
user answers 'no'.

Introduce a `retry_ask_yes_no()` helper function that handles retry with
small delay, asking the user, and restoring `errno`.

Note that in `mingw_unlink()`, we include the `_wchmod()` call in the
retry loop (which may fail if the file is locked exclusively).

In `mingw_rmdir()`, we include special error handling in the retry loop.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Bill Zissimopoulos
543a91ccf9 mingw: compute the correct size for symlinks in mingw_lstat()
POSIX specifies that upon successful return from `lstat()`: "the
value of the st_size member shall be set to the length of the pathname
contained in the symbolic link not including any terminating null byte".

Git typically doesn't trust the `stat.st_size` member of symlinks (e.g.
see `strbuf_readlink()`). Therefore, it is tempting to save on the extra
overhead of opening and reading the reparse point merely to calculate
the exact size of the link target.

This is, in fact, what Git for Windows did, from May 2015 to May 2020.
At least almost: some functions take shortcuts if `st_size` is 0 (e.g.
`diff_populate_filespec()`), hence Git for Windows hard-coded the length
of all symlinks to MAX_PATH.

This did cause problems, though, specifically in Git repositories
that were also accessed by Git for Cygwin or Git for WSL. For example,
doing `git reset --hard` using Git for Windows would update the size of
symlinks in the index to be MAX_PATH; at a later time Git for Cygwin
or Git for WSL would find that symlinks have changed size during `git
status` and update the index. And then Git for Windows would think that
the index needs to be updated. Even if the symlinks did not, in fact,
change. To avoid that, the correct size must be determined.

Signed-off-by: Bill Zissimopoulos <billziss@navimatics.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Karsten Blees
8a4f4131aa mingw: teach dirent about symlinks
Move the `S_IFLNK` detection to `file_attr_to_st_mode()`.

Implement `DT_LNK` detection in dirent.c's `readdir()` function.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Karsten Blees
2c37842ff9 mingw: let mingw_lstat() error early upon problems with reparse points
When obtaining lstat information for reparse points, we need to call
`FindFirstFile()` in addition to `GetFileInformationEx()` to obtain
the type of the reparse point (symlink, mount point etc.). However,
currently there is no error handling whatsoever if `FindFirstFile()`
fails.

Call `FindFirstFile()` before modifying the `stat *buf` output parameter
and error out if the call fails.

Note: The `FindFirstFile()` return value includes all the data
that we get from `GetFileAttributesEx()`, so we could replace
`GetFileAttributesEx()` with `FindFirstFile()`. We don't do that because
`GetFileAttributesEx()` is about twice as fast for single files. I.e.
we only pay the extra cost of calling `FindFirstFile()` in the rare case
that we encounter a reparse point.

Please also note that the indentation the remaining reparse point
code changed, and hence the best way to look at this diff is with
`--color-moved -w`. That code was _not_ moved because a subsequent
commit will move it to an altogether different function, anyway.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:55 -08:00
Karsten Blees
882e5e0528 mingw: drop the separate do_lstat() function
With the new `mingw_stat()` implementation, `do_lstat()` is only called
from `mingw_lstat()` (with the function parameter `follow == 0`). Remove
the extra function and the old `mingw_stat()`-specific (`follow == 1`)
logic.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:54 -08:00
Karsten Blees
48bc5094de mingw: implement stat() with symlink support
With respect to symlinks, the current `mingw_stat()` implementation is
almost identical to `mingw_lstat()`: except for the file type (`st_mode
& S_IFMT`), it returns information about the link rather than the target.

Implement `mingw_stat()` by opening the file handle requesting minimal
permissions, and then calling `GetFileInformationByHandle()` on it. This
way, all links are resolved by the Windows file system layer.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:54 -08:00
Karsten Blees
3b96b99683 mingw: don't call GetFileAttributes() twice in mingw_lstat()
The Win32 API function `GetFileAttributes()` cannot handle paths with
trailing dir separators. The current `mingw_stat()`/`mingw_lstat()`
implementation calls `GetFileAttributes()` twice if the path has
trailing slashes (first with the original path that was passed as
function parameter, and and a second time with a path copy with trailing
'/' removed).

With the conversion to wide Unicode, we get the length of the path for
free, and also have a (wide char) buffer that can be modified. This
makes it easy to avoid that extraneous Win32 API call.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:32:54 -08:00
Junio C Hamano
ec13dca8d0 Merge branch 'js/prep-symlink-windows' into js/symlink-windows
* js/prep-symlink-windows:
  trim_last_path_component(): avoid hard-coding the directory separator
  strbuf_readlink(): support link targets that exceed 2*PATH_MAX
  strbuf_readlink(): avoid calling `readlink()` twice in corner-cases
  init: do parse _all_ core.* settings early
  mingw: do resolve symlinks in `getcwd()`
  t7800: work around the MSYS path conversion on Windows
  t6423: introduce Windows-specific handling for symlinking to /dev/null
  t1305: skip symlink tests that do not apply to Windows
  t1006: accommodate for symlink support in MSYS2
  t0600: fix incomplete prerequisite for a test case
  t0301: another fix for Windows compatibility
  t0001: handle `diff --no-index` gracefully
  mingw: special-case `open(symlink, O_CREAT | O_EXCL)`
  apply: symbolic links lack a "trustable executable bit"
  t9700: accommodate for Windows paths
2026-01-09 18:32:29 -08:00
Karsten Blees
aa7b8864d8 trim_last_path_component(): avoid hard-coding the directory separator
Currently, this function hard-codes the directory separator as the
forward slash.

However, on Windows the backslash character is valid, too. And we want
to call this function in the upcoming support for symlinks on Windows
with the symlink targets (which naturally use the canonical directory
separator on Windows, which is _not_ the forward slash).

Prepare that function to be useful also in that context.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:28:37 -08:00
Johannes Schindelin
21f368daab strbuf_readlink(): support link targets that exceed 2*PATH_MAX
The `strbuf_readlink()` function refuses to read link targets that
exceed 2*PATH_MAX (even if a sufficient size was specified by the
caller).

The reason that that limit is 2*PATH_MAX instead of PATH_MAX is that
the symlink targets do not need to be normalized. After running
`ln -s a/../a/../a/../a/../b c`, the target of the symlink `c` will not
be normalized to `b` but instead be much longer. As such, symlink
targets' lengths can far exceed PATH_MAX.

They are frequently much longer than 2*PATH_MAX on Windows, which
actually supports paths up to 32,767 characters, but sets PATH_MAX to
260 for backwards compatibility. For full details, see
https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation

Let's just hard-code the limit used by `strbuf_readlink()` to 32,767 and
make it independent of the current platform's PATH_MAX.

Based-on-a-patch-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:28:36 -08:00
Karsten Blees
0fcbb57f97 strbuf_readlink(): avoid calling readlink() twice in corner-cases
The `strbuf_readlink()` function calls `readlink()`` twice if the hint
argument specifies the exact size of the link target (e.g. by passing
stat.st_size as returned by `lstat()`). This is necessary because
`readlink(..., hint) == hint` could mean that the buffer was too small.

Use `hint + 1` as buffer size to prevent this.

Signed-off-by: Karsten Blees <karsten.blees@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-01-09 18:28:36 -08:00