Rebase to Git for Windows 2.56.0-rc2 - #991
Merged
Johannes Schindelin (dscho) merged 364 commits intoSep 23, 2026
Merged
Conversation
Create t/helper/test-gvfs-protocol.c and t/t5799-gvfs-helper.sh to test gvfs-helper. Create t/helper/test-gvfs-protocol.c as a stand-alone web server that speaks the GVFS Protocol [1] and serves loose objects and packfiles to clients. It is borrows heavily from the code in daemon.c. It includes a "mayhem" mode to cause various network and HTTP errors to test the retry/recovery ability of gvfs-helper. Create t/t5799-gvfs-helper.sh to test gvfs-helper. [1] https://github.com/microsoft/VFSForGit/blob/master/Protocol.md Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The gvfs-helper allows us to download prefetch packs using a simple subprocess call. The gvfs-helper-client.h method will automatically compute the timestamp if passing 0, and passing NULL for the number of downloaded packs is valid. Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
- include `scalar` - build signed .dmg & .pkg for target OS version 10.6 - upload artifacts to workflow Co-authored-by: Lessley Dennington <ldennington@github.com>
gvfs-helper prints a "loose <oid>" or "packfile <name>" messages after they are received to help invokers update their in-memory caches. Move the code to accumulate these messages in the result_list into the install_* functions rather than waiting until the end. POST requests containing 1 object may return a loose object or a packfile depending on whether the object is a commit or non-commit. Delaying the message generation just complicated the caller. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Teach gvfs-helper to better support the concurrent fetching of the same packfile by multiple instances. If 2 instances of gvfs-helper did a POST and requested the same set of OIDs, they might receive the exact same packfile (same checksum SHA). Both processes would then race to install their copy of the .pack and .idx files into the ODB/pack directory. This is not a problem on Unix (because of filesystem semantics). On Windows, this can cause an EBUSY/EPERM problem for the loser while the winner is holding a handle to the target files. (The existing packfile code already handled simple the existence and/or replacement case.) The solution presented here is to silently let the loser claim victory IIF the .pack and .idx are already present in the ODB. (We can't check this in advance because we don't know the packfile SHA checksum until after we receive it and run index-pack.) We avoid using a per-packfile lockfile (or a single lockfile for the `vfs-` prefix) to avoid the usual issues with stale lockfiles. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
- include `scalar` - build & upload unsigned .deb package Co-authored-by: Lessley Dennington <ldennington@github.com> Co-authored-by: Sverre Johansen <sverre.johansen@gmail.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Earlier versions of the test always returned a packfile in response to a POST. Now we look at the number of objects in the POST request. If > 1, always send a packfile. If = 1 and it is a commit, send a packfile. Otherwise, send a loose object. This is to better model the behavior of the GVFS server/protocol which treats commits differently. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
When using the GVFS protocol, we should _never_ call "git fetch-pack" to attempt downloading a pack-file via the regular Git protocol. It appears that the mechanism that prevented this in the VFS for Git world is due to the read-object hook populating the commits at the new ref tips in a different way than the gvfs-helper does. By acting as if the fetch-pack succeeds here in remote-curl, we prevent a failed fetch. Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Construct 2 new unit tests to explicitly verify the use of `--fallback` and `--no-fallback` arguments to `gvfs-helper`. When a cache-server is enabled, `gvfs-helper` will try to fetch objects from it rather than the origin server. If the cache-server fails (and all cache-server retry attempts have been exhausted), `gvfs-helper` can optionally "fallback" and try to fetch the objects from the origin server. (The retry logic is also applied to the origin server, if the origin server fails on the first request.) Add new unit tests to verify that `gvfs-helper` respects both the `--max-retries` and `--[no-]fallback` arguments. We use the "http_503" mayhem feature of the `test_gvfs_protocol` server to force a 503 response on all requests to the cache-server and the origin server end-points. We can then count the number of connection requests that `gvfs-helper` makes to the server and confirm both the per-server retries and whether fallback was attempted. Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
- sign using Azure-stored certificates & client - sign on Windows agent via python script - job skipped if credentials for accessing certificate aren't present Co-authored-by: Lessley Dennington <ldennington@github.com> Co-authored-by: Sverre Johansen <sverre.johansen@gmail.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
By default, GVFS Protocol-enabled Scalar clones will fall back to the origin server if there is a network issue with the cache servers. However (and especially for the prefetch endpoint) this may be a very expensive operation for the origin server, leading to the user being throttled. This shows up later in cases such as 'git push' or other web operations. To avoid this, create a new config option, 'gvfs.fallback', which defaults to true. When set to 'false', pass '--no-fallback' from the gvfs-helper client to the child gvfs-helper server process. This will allow users who have hit this problem to avoid it in the future. In case this becomes a more widespread problem, engineering systems can enable the config option more broadly. Enabling the config will of course lead to immediate failures for users, but at least that will help diagnose the problem when it occurs instead of later when the throttling shows up and the server load has already passed, damage done. Signed-off-by: Derrick Stolee <stolee@gmail.com>
- create release & uploads artifact using Octokit - use job "if" condition to handle uploading signed *or* unsigned .deb Co-authored-by: Lessley Dennington <ldennington@github.com>
Update `git archive` tree-ish argument from `HEAD^{tree}` to `HEAD`. By
using a commit (rather than tree) reference, the commit hash will be stored
as an extended pax header, extractable git `git get-tar-commit-id`.
The intended use-case for this change is building `git` from the output of
`make dist` - in combination with the ability to specify a fallback
`GIT_BUILT_FROM_COMMIT`, a user can extract the commit ID used to build the
archive and set it as `GIT_BUILT_FROM_COMMIT`. The result is fully-populated
information for the commit hash in `git version --build-options`.
Signed-off-by: Victoria Dye <vdye@github.com>
It is possible that a loose object that is written from a GVFS protocol "get object" request does not match the expected hash. Error out in this case. 2021-10-30: The prototype for read_loose_object() changed in 31deb28 (fsck: don't hard die on invalid object types, 2021-10-01) and 96e41f5 (fsck: report invalid object type-path combinations, 2021-10-01). Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
When we create temp files for downloading packs, we use a name based on the current timestamp. There is no randomness in the name, so we can have collisions in the same second. Retry the temp pack names using a new "-<retry>" suffix to the name before the ".temp". Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Add "mayhem" keys to generate corrupt packfiles and/or corrupt idx files in prefetch by trashing the trailing checksum SHA. Add unit tests to t5799 to verify that `gvfs-helper` detects these corrupt pack/idx files. Currently, only the (bad-pack, no-idx) case is correctly detected, Because `gvfs-helper` needs to locally compute the idx file itself. A test for the (bad-pack, any-idx) case was also added (as a known breakage) because `gvfs-helper` assumes that when the cache server provides both, it doesn't need to verify them. We will fix that assumption in the next commit. Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
Create new `cache_http_503` mayhem method where only the cache server sends a 503. The normal `http_503` directs both cache and origin server to send 503s. This will be used to help test fallback. Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
It really does not make sense to run that workflow in any fork of git-for-windows/git. Typically, it is enough to simply disable it (since it is a scheduled workflow, it is disabled by default in any new fork). However, in microsoft/git, we switch the default branch whenever we rebase to a new upstream version, and every time we do so, this scheduled workflow gets re-enabled. Let's just delete it in microsoft/git and never be bothered by it again. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Update build-git-installers workflow to publish `microsoft/git`'s GPG public key as part of each release. Add explanation for how to use this key to verify the Debian package's signature to the README.
Set the `GIT_BUILT_FROM_COMMIT` based on the version specified in the `make dist` output archive header. This ensures the commit hash is shown in `git version --build-options`. Signed-off-by: Victoria Dye <vdye@github.com>
Teach helper/test-gvfs-protocol to be able to send corrupted loose blobs. Add unit test for gvfs-helper to detect receipt of a corrupted loose blob. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
`sparse` complains with an error message like this: gvfs-helper.c:2912:17: error: expression using sizeof on a function The culprit is this line: curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite); Similar lines exist in `http-push.c` and other files that are in upstream Git, and to avoid these bogus warnings, they are already exempted from `sparse`'s tender, loving care. We simply add `gvfs-helper.c` to that list. Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
The GVFS cache server can return multiple pairs of (.pack, .idx) files. If both are provided, `gvfs-helper` assumes that they are valid without any validation. This might cause problems if the .pack file is corrupt inside the data stream. (This might happen if the cache server sends extra unexpected STDERR data or if the .pack file is corrupt on the cache server's disk.) All of the .pack file verification logic is already contained within `git index-pack`, so let's ignore the .idx from the data stream and force compute it. This defeats the purpose of some of the data cacheing on the cache server, but safety is more important. Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
For Scalar and VFS for Git, we use an alternate as a shared object cache. We need to enable the maintenance builtin to work on that shared object cache, especially in the background. 'scalar run <task>' would set GIT_OBJECT_DIRECTORY to handle this. We set GIT_OBJECT_DIRECTORY based on the gvfs.sharedCache config, but we also need the checks in pack_loose() to look at that object directory instead of the current ODB's. Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
When the virtualfilesystem is enabled the previous implementation of clear_ce_flags would iterate all of the cache entries and query whether each one is in the virtual filesystem to determine whether to clear one of the SKIP_WORKTREE bits. For each cache entry, we would do a hash lookup for each parent directory in the is_included_in_virtualfilesystem function. The former approach is slow for a typical Windows OS enlistment with 3 million files where only a small percentage is in the virtual filesystem. The cost is O(n_index_entries * n_chars_per_path * n_parent_directories_per_path). In this change, we use the same approach as apply_virtualfilesystem, which iterates the set of entries in the virtualfilesystem and searches in the cache for the corresponding entries in order to clear their flags. This approach has a cost of O(n_virtual_filesystem_entries * n_chars_per_path * log(n_index_entries)). The apply_virtualfilesystem code was refactored a bit and modified to clear flags for all names that 'alias' a given virtual filesystem name when ignore_case is set. n_virtual_filesystem_entries is typically much less than n_index_entries, in which case the new approach is much faster. We wind up building the name hash for the index, but this occurs quickly thanks to the multi-threading. Signed-off-by: Neeraj Singh <neerajsi@ntdev.microsoft.com>
This was disabled by a0da6de (ci: only run win+VS build & tests in Git for Windows' fork, 2022-12-19) to avoid other forks doing too many builds. But we want to keep these builds for the microsoft/git fork. Signed-off-by: Derrick Stolee <derrickstolee@github.com>
For the same rationale as the preceding release-homebrew commit, port the body of `.github/workflows/release-vfsforgit.yml` into a POSIX-sh script that the operator invokes by hand while promoting a pre-release to a full release. Given a release tag on microsoft/git, the script opens a pull request against microsoft/VFSForGit that bumps the `GIT_VERSION` default in `.github/workflows/build.yaml` so that VFSForGit builds pick up the newly promoted release by default. The operator's own `gh auth login` session already has push access to microsoft/VFSForGit, so no PAT and no Key Vault-backed secret are needed. The commit and the pull request are attributed to that user rather than to `github-actions[bot]`, which also makes the change to the downstream repository traceable to an identifiable human who can be pinged for follow-up. One portability wart worth calling out: the version bump uses the `<in >out && mv -f out in` idiom rather than `sed -i`, because the `-i` flag has incompatible spellings between GNU sed on Linux (which accepts `-i` with no argument) and BSD sed on macOS (which requires an explicit empty suffix, `-i ''`). The script is expected to run from either platform, so it sticks to the portable form and stays plain POSIX sh throughout. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
…d-port of #915) (#921) Forward-port of #915 ("checkout: preserve skip-worktree for virtual filesystem paths", merged into `vfs-2.53.0` as ea3eb21) to `vfs-2.54.0`. Cherry-picked from the underlying PR-branch commit d40f13b (so the original well-crafted commit message and Tyrie Vella's authorship are preserved). One auto-merge in `builtin/checkout.c` resolved cleanly without conflicts.
Same rationale as the two prior scripts (release-homebrew.sh, release-vfsforgit.sh): replace a CI-driven fan-out step with a hand-run script that reads its GitHub token from `gh auth token`, sidestepping the PAT/Azure Key Vault dance. This one _must_ be run on Windows (or in WSL) because `wingetcreate.exe`, the tool that authors the manifest and opens the PR against microsoft/winget-pkgs, is Windows-only; the superseded workflow already ran on `windows-latest` for that reason, and neither the operator nor the automation ever invoked this step from macOS or Linux. microsoft/git tags look like `vX.Y.Z.vfs.N.M`, but winget wants a purely dotted numeric version, so the script strips the leading `v` and the `vfs.` segment to produce `X.Y.Z.N.M` (for example, `v2.54.0.vfs.0.4` becomes `2.54.0.0.4`), matching what the previous workflow emitted. The tag is parsed with `-not ($tag -match ...)` rather than the seemingly equivalent `-notmatch`, because PowerShell's `-notmatch` operator does not populate the `$Matches` automatic variable, yet the two capture groups are read as `$Matches[1]` and `$Matches[2]` immediately afterwards. See https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comparison_operators for the documented behaviour. `wingetcreate submit` pushes to the operator's personal fork of microsoft/winget-pkgs and opens a PR from there; if that fork is stale, submit fails with "The forked repository could not be synced". The script therefore issues a `POST /repos/<user>/winget-pkgs/merge-upstream` first, and treats a 404 as fine, since wingetcreate creates the fork on demand at submit time when none exists. Assisted-by: Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The Windows runners used by `vfs-functional-tests.yml` ship `rustup` plus a `*-pc-windows-msvc` default toolchain (see https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md and https://github.com/actions/partner-runner-images/blob/main/images/arm-windows-11-image.md), but no precompiled `std` for `*-pc-windows-gnu` or `*-pc-windows-gnullvm`. With the Makefile now picking a GCC-compatible target triple based on `$(MSYSTEM)`, the build step needs that precompiled `std` to be installed before invoking `make`, otherwise `cargo build --target <triple>` fails to find a usable `std` for the chosen target. Add a step between the SDK setup and the `make` invocation that selects the matching triple from `$MSYSTEM` (which `git-for-windows/setup-git-for-windows-sdk` exports for every subsequent step) and runs `rustup target add` for it. The mapping mirrors what `config.mak.uname` derives from `$(MSYSTEM)` and `$(HOST_CPU)`, just enumerated explicitly here since CI has direct knowledge of which MSYS2 subsystems the matrix actually exercises (`CLANGARM64` for the ARM64 runner, `MINGW64` for the x86_64 runner). For a `staticlib` crate-type `cargo build` does not invoke an external linker, so no further toolchain components (e.g. the `gnullvm` LLVM linker) need to be installed; `rustup target add` alone is sufficient. Assisted-by: Claude Opus 4.7 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Some users reported issues of repeated messages: fatal: recursion detected in die handler This wasn't happening every time, but we eventually captured a GIT_TRACE2_PERF log file with this issue and revealed an interesting internal detail, failing with this message: unable to format message: %4d-%02d-%02dT%02d:%02d:%02d.%06ldZ This specific format string tracks to tr2_tbuf_utc_datetime_extended() in trace2/tr2_tbuf.c. This logic began as tr2_tbuf_utc_time() in ee4512e (trace2: create new combined trace facility, 2019-02-22) but was later split in bad229a (trace2: clarify UTC datetime formatting, 2019-04-15). This use of xsnprintf() is writing a very specific datetime format into a 32-character buffer. The format requires that the input data will not overflow the format digits or the buffer will not hold the result. Since we are using xsnprintf() here, those failures turn into die() events. This method and its siblings, tr2_tbuf_local_time() and tr2_tbuf_utc_datetime(), are used in the tracing library. The extended form is used only for the 'event' format, which these users were using via a config setting for use in client-side telemetry. The non-extended form is used to help generate the 'SID' that defines the process in the traces. Not only are these inappropriate times for a failure, but the extended method is called specifially during the 'atexit' event, which was triggering this problem in a loop as the 'atexit' event would be retriggered by the die(). I could not determine the exact cause of why these errors started occuring in a bunch. My best guess is that these users are dogfooding an early operating system version that is more likely to fail in the gettimeofday() function and thus leaves the structures uninitialized and potentially violating the expected values. However, for full defense-in-depth I made several modifications: 1. Both 'tv' and 'tm' structs are initialized with zero values, allowing an erroring gettimeofday() or gmtime_r() method to leave them zero-valued. A zero-valued date is better than a die() here. 2. Replace the use of xsnprintf() with snprintf() to avoid the possibility of calling die() here. Instead, check the response to see if there was a failure. On failure, put a blank value into the buffer instead of possibly allowing a value that would not format correctly for a trace2 consumer. This value should be seen as obviously wrong and therefore signals a problem. As the core issue in this code seems to require a system method returning an error, no test accompanies this change. This change removes all uses of xsnprintf() from the trace2/ directory. There are two uses of xstrdup() that could be considered for removal, but they only die() on out-of-memory errors instead of formatting issues. I chose to leave those in place for now. Signed-off-by: Derrick Stolee <stolee@gmail.com>
This PR simply ports #952 to the `vfs-2.55.0` branch. It intentionally collapses the commits to make future rebases quicker.
In virtual filesystem (VFS/GVFS) mode, reset --mixed failed to report
hydrated files as modified. A hydrated file is one that has been read
(e.g. via blame or cat-file) and materialized on disk by ProjFS, but
not modified — so it is not in GVFS's ModifiedPaths database and
retains the skip-worktree bit in the index.
The existing VFS-specific code in update_index_from_diff() used
file_exists() to decide whether to clear skip-worktree:
- Files NOT on disk (virtual/placeholder): file_exists() returns
false, skip-worktree is cleared, and the pre-reset content is
written to disk via checkout_entry(). These files correctly
appear as modified. This path remains unchanged.
- Files already on disk (hydrated): file_exists() returns true,
so the code left skip-worktree set. refresh_index() then skipped
the file entirely, hiding the working-tree vs index mismatch.
The file was invisible to both the reset output and subsequent
git status.
Fix this by always clearing skip-worktree (respect_skip_worktree = 0)
for all entries processed by update_index_from_diff() when VFS mode is
active. The file_exists() check now only controls whether pre-reset
content needs to be written to disk — it no longer affects the
skip-worktree decision.
After the reset, GVFS's GitIndexParser detects the cleared
skip-worktree bits via the post-index-change hook and adds the
affected paths to ModifiedPaths, so subsequent git commands also
see them correctly.
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Users were noticing some cases of infinite loops with the error message: ``` fatal: recursion detected in die handler ``` It's only happening for repos with a post-command hook, but it's not deterministic. I'm not sure what is triggering the problem, but the post-command hook is definitely able to recurse with its existing logic around the `run_post_hook` variable. Move this earlier to avoid a potential double-call. It's a fixup to the introduction of the method, which may cause conflicts with later adjustments to this method still in the branch thicket (but maybe those should be squashed, too). See #955 for the version on 2.54.0.
When pushing from a repository that uses the GVFS Protocol, `git push` spawns `git pack-objects --all-progress-implied --revs --stdout --thin -q` and feeds it revision parameters on stdin: the advertised refs and negotiated objects as negative (exclusion) tips, plus each ref's old and new tips. Normally feed_object() omits a negative object that is not present locally, but the core.gvfs GVFS_MISSING_OK bit disables that check so that missing negatives are still fed. That bypass is actively harmful under the GVFS Protocol. pack-objects adds `--objects-edge` for `--thin` and, while marking edges uninteresting and hunting for preferred delta bases, reads the tree of every fed exclusion. For an exclusion the client does not have locally, that read lazily downloads the object, issuing one gh_client__get_ immediate request per advertised ref. A scalar clone against a server that advertises many refs therefore triggers a storm of immediate object fetches during an ordinary push. Partial clone deliberately assumes the objects behind our refs are already present and never fetches them for a push. Restore that behavior for the GVFS Protocol behind a new opt-in config, gvfs.negativeRefCheck. When set, `git push` performs a non-fetching existence check -- odb_has_object() with flags 0 implies OBJECT_INFO_QUICK | OBJECT_INFO_SKIP_FETCH_OBJECT, so the probe never fetches -- and omits any advertised object it does not have, exactly as Git does without the GVFS_MISSING_OK bit. The decision is computed once in pack_objects() because advertised ref lists can be large. The config defaults to false, so the legacy GVFS_MISSING_OK behavior is unchanged unless an operator opts in, keeping the fallout controllable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
#963) This is a companion of #935, porting the changes from vfs-2.54.0 to vfs-2.55.0. ## Problem In virtual filesystem (VFS/GVFS) mode, `reset --mixed` fails to report hydrated files as modified. A **hydrated file** is one that has been read (e.g., via `blame` or `cat-file`) and materialized on disk by ProjFS, but not modified — so it is not in GVFS's ModifiedPaths database and retains the `skip-worktree` bit in the index. ### Reproduction 1. `gvfs clone` a repo 2. `git blame Readme.md` — hydrates the file (ProjFS materializes content on disk) 3. `git reset --mixed HEAD~1` (where `Readme.md` differs between HEAD and HEAD~1) 4. **Expected:** `Readme.md` appears in reset output and `git status` shows it as modified 5. **Actual:** `Readme.md` is missing from output; `git status` reports clean ### Root cause The VFS-specific code in `update_index_from_diff()` uses `file_exists()` to decide whether to clear `skip-worktree`: - **Files NOT on disk** (virtual/placeholder): `file_exists()` returns false → `skip-worktree` cleared, pre-reset content written to disk via `checkout_entry()` → correctly reported as modified ✓ - **Files on disk** (hydrated): `file_exists()` returns true → `skip-worktree` left set → `refresh_index()` skips the entry → invisible to status ✗ The original code assumed that if a file exists on disk, it must already be tracked properly. But hydrated-but-not-modified files exist on disk with stale content and are NOT in ModifiedPaths. ## Fix Always clear `skip-worktree` (`respect_skip_worktree = 0`) for all entries processed by `update_index_from_diff()` when VFS mode is active. The `file_exists()` check now only controls whether pre-reset content needs to be written to disk — it no longer gates the skip-worktree decision. After the reset, GVFS's `GitIndexParser` detects the cleared skip-worktree bits via the `post-index-change` hook and adds affected paths to ModifiedPaths, so subsequent git commands also see them correctly. ### Before (buggy) ```c if (core_virtualfilesystem && !file_exists(two->path)) { respect_skip_worktree = 0; // only for missing files // ... write content to disk ... } ``` ### After (fixed) ```c if (core_virtualfilesystem) { respect_skip_worktree = 0; // for ALL changed entries if (!file_exists(two->path)) // only write content for missing files { // ... write content to disk ... } } ``` ## Testing - 3 new tests in `t1093-virtualfilesystem.sh`: - **Hydrated file**: file exists on disk, should appear in reset output - **Non-hydrated file**: file missing from disk, should be written and appear in output - **Partial reset**: unchanged files retain skip-worktree - Verified manually against a real GVFS enlistment: GVFS and control repo now produce identical output (224 modified files including `Readme.md`) - All 25 existing `t1093` tests pass
When using the GVFS protocol with 'scalar clone', the first 'git fetch' uses the prefetch endpoint to download commits and trees so history operations are usable immediately after cloning. Some users want to optimize for the initial usability of the repository, and they don't need the full history available right away. They are prepared to wait for future fetches (perhaps in the background) doing that work for them. Add a new --no-prefetch option that skips the initial prefetch. This is implemented by using '-c core.gvfs=X' arguments in the underlying fetch operation to temporarily avoid the prefetch operation for that subcommand only. It's important that this does not actually stop prefetches forever, though that can be adjusted by flipping the appropriate bit in the core.gvfs config option. Signed-off-by: Derrick Stolee <stolee@gmail.com>
The object database refactor that introduced per-source object stores (cb506a8 "odb: introduce \"files\" source" and the surrounding series, first released in v2.54.0) changed how do_oid_object_info_extended() searches for an object. It now iterates the sources and, within each source, consults that source's packfiles and then its loose object store before moving on to the next source. Before that series the search consulted every packfile -- across the primary object directory and all alternates -- before it looked at any loose object. The refactor reversed that for the multi-source case: for an object that lives in an alternate's packfile, the primary source's loose object store is now consulted first. That loose lookup is a filesystem stat(), and because callers such as cache_tree_fully_valid() pass ODB_HAS_OBJECT_RECHECK_PACKED (which clears OBJECT_INFO_QUICK) the cached-loose-index fast path is skipped and a real stat() runs for every such object. In a repository that keeps its objects in an alternate -- the common arrangement for VFS for Git and Scalar enlistments, where a shared object cache is mounted as an alternate -- this is a steep penalty. cache_tree_fully_valid() walks the whole cache tree and calls odb_has_object() for every node; on an enlistment with a ~2.4M-entry index that is ~380k objects, each incurring a wasted stat() on the primary loose store. A same-commit branch switch spent ~32s in cache_tree_fully_valid() (two calls of ~16s), observed in the field as a ~2x rise in median checkout duration after the client carrying the refactor rolled out. Restore the previous ordering without undoing the per-source encapsulation: when there is more than one source, scan the packfiles of every source first (OBJECT_INFO_SKIP_LOOSE) and only then consult each source's loose store (OBJECT_INFO_SKIP_PACKED). The single-source case is unchanged, so repositories without alternates keep the existing path. With the fix the same branch switch spends ~2s in cache_tree_fully_valid(), the ~380k wasted stat()s are gone, and performance matches versions predating the refactor. Assisted-by: Claude Opus 4.8 Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
When pushing from a repository that uses the GVFS Protocol, `git push`
spawns `git pack-objects --all-progress-implied --revs --stdout --thin
-q` and feeds it revision parameters on stdin: the advertised refs and
negotiated objects as negative (exclusion) tips, plus each ref's old and
new tips. Normally feed_object() omits a negative object that is not
present locally, but the core.gvfs GVFS_MISSING_OK bit disables that
check so that missing negatives are still fed.
That bypass is actively harmful under the GVFS Protocol. pack-objects
adds `--objects-edge` for `--thin` and, while marking edges
uninteresting and hunting for preferred delta bases, reads the tree of
every fed exclusion. For an exclusion the client does not have locally,
that read lazily downloads the object, issuing one gh_client__get_
immediate request per advertised ref. A scalar clone against a server
that advertises many refs therefore triggers a storm of immediate object
fetches during an ordinary push.
Partial clone deliberately assumes the objects behind our refs are
already present and never fetches them for a push. Restore that behavior
for the GVFS Protocol behind a new opt-in config, gvfs.negativeRefCheck.
When set, `git push` performs a non-fetching existence check --
odb_has_object() with flags 0 implies OBJECT_INFO_QUICK |
OBJECT_INFO_SKIP_FETCH_OBJECT, so the probe never fetches -- and omits
any advertised object it does not have, exactly as Git does without the
GVFS_MISSING_OK bit. The decision is computed once in pack_objects()
because advertised ref lists can be large.
The config defaults to false, so the legacy GVFS_MISSING_OK behavior is
unchanged unless an operator opts in, keeping the fallout controllable.
* [X] This change only applies to interactions with Azure DevOps and the
GVFS Protocol.
Prepare the configuration surface for parallel POST workers before the worker implementation is introduced. Add gvfs.postThreads with a default of one so this commit does not change request execution on its own. Document the intended concurrent behavior and clamp values below one. Later commits in the series consume the value while introducing the parallel success path and then its complete failure handling. Helped-by: GPT-5.6 Sol Co-authored-by: Neil Kainga <t-neilkainga@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Neil Kainga <t-neilkainga@microsoft.com> Signed-off-by: Derrick Stolee <stolee@gmail.com>
When a user uses the --no-prefetch option, they do not get batched commit and tree packfiles before attempting a checkout. Thankfully, the GVFS Protocol has a mechanism to help here: the /gvfs/objects POST endpoint can ask for a commit and that will trigger a download of all trees needed for a checkout of that commit. When using --no-prefetch and the GVFS protocol, run this extra POST request before running a checkout. Signed-off-by: Derrick Stolee <stolee@gmail.com>
Switching branches in a VFS for Git or Scalar enlistment became drastically slower in Git v2.55. The cause is the interaction of two independent changes, not a single one. Commit 062b914 (treewide: convert users of repo_has_object_file() to has_object()), first released in v2.50, accidentally inverted the object existence check in cache_tree_fully_valid(), so that function bailed out at the root instead of validating the cache tree recursively. Commit 5217312 (cache-tree: fix inverted object existence check in cache_tree_fully_valid), first released in v2.55, correctly restored the recursion. In between, v2.54's per-source object database refactor changed the cross-source lookup order: instead of scanning all packfiles before any loose object store, it scans packed then loose per source. That change caused no observable checkout regression in v2.54 precisely because the inverted check prevented recursion and thereby masked the per-object cost. Conversely, v2.49 did recurse, yet stayed fast because its global pack-first lookup found the objects in an alternate's packs before attempting any loose lookup. v2.55 is therefore the first version combining recursive cache-tree validation with per-source packed-then-loose lookup, at a cost of roughly one wasted primary loose-object lstat() per cache-tree node. In enlistments that use an alternate object cache, that cost is severe. cache_tree_fully_valid() calls odb_has_object() hundreds of thousands of times, and ODB_HAS_OBJECT_RECHECK_PACKED clears OBJECT_INFO_QUICK, so each call performs a real lstat() in the primary loose object store before the object is found in the alternate's packfile. On a measured index with about 2.4M entries: 381,006 cache-tree nodes, 380,944 wasted lstat() calls, not a single miss; cache-tree validation took about 32 seconds and switching to a branch pointing at the same commit about 36 seconds. This merge restores the all-sources-packed-before-all-sources-loose order whenever more than one source is present. The wasted stats are gone, validation drops to about 2 seconds and branch switching to about 6-7 seconds. Presence semantics are unchanged. The trade-off needs to be stated plainly: the mitigation lives in the shared object-info lookup, which is a slightly incorrect representation layer for a problem specific to presence-only queries via odb_has_object(). When an object is loose in the primary and packed in an alternate, metadata callers now observe the alternate's packed representation. Observable differences include reported on-disk size, mtime, delta base, corruption handling, and promisor-pack classification. Object content, type and logical size, as well as presence, remain correct because objects are content-addressed, which bounds the fallout to the representation level. We accept those behavior changes deliberately in exchange for fixing an intolerable regression in this fork now. The architecturally correct fix is upstream's plan to move alternate handling into the files backend. That backend would own both the primary and the alternates and could therefore scan all relevant packs before any loose-object lookup without violating the abstraction. The upstream contributor estimates that work at "three to four patch years", i.e. likely months in Git project time, and probably not before Git 2.56. microsoft/git cannot wait that long. This merge is consequently an explicitly temporary mitigation specific to Microsoft Git. Once upstream's fix lands, this implementation should be replaced and the regression test reassessed. That test currently asserts packed-versus-loose selection through %(deltabase), which necessarily pins representation ordering and may not survive the upstream architecture. A future replacement could instead verify the absence of the unwanted lstat() calls directly, possibly as a Linux-only strace test, since the behavior itself is platform-independent.
The parallel POST implementation needs standalone curl handles with the same runtime settings as handles allocated through get_active_slot(). Creating raw handles would otherwise omit cookies, configured host resolutions, redirect policy, IP selection, and current authentication defaults. Extract the per-request handle preparation into a shared helper and use it from get_active_slot(). Expose a function that duplicates the initialized default handle and applies the same preparation for callers that manage a handle outside the active-slot machinery. Also expose whether cookies are configured. Libcurl cannot safely share cookie state across concurrently performing handles, so callers can retain an established sequential path in that case. Helped-by: GPT-5.6 Sol Co-authored-by: Neil Kainga <t-neilkainga@microsoft.com> Signed-off-by: Neil Kainga <t-neilkainga@microsoft.com> Signed-off-by: Derrick Stolee <stolee@gmail.com>
When using the GVFS protocol with `scalar clone`, the first `git fetch` issues a `/gvfs/prefetch` request to download the commits and trees that back the checked-out branch, so history operations are usable immediately after cloning. For large repositories this prefetch can dominate the clone time. Some users would rather optimize for the initial usability of the working tree and do not need full history right away; they are content to let a later fetch (including background maintenance) download the prefetch data for them. This PR adds a `--[no-]prefetch` option to `scalar clone`. With `--no-prefetch`, the initial `/gvfs/prefetch` request is skipped so the worktree becomes ready as quickly as possible. ### Implementation The prefetch-during-fetch behavior is gated by the `GVFS_PREFETCH_DURING_FETCH` bit (`1 << 7`) in `core.gvfs`, which `scalar clone` sets as part of the value `150`. Rather than persisting a different `core.gvfs` value (which would disable prefetching *forever*), `--no-prefetch` only clears that bit for the single `git fetch` invocation performed during the clone, by passing `-c core.gvfs=<value without the prefetch bit>`. The persisted `core.gvfs` is left untouched, so: - the initial clone skips the prefetch and finishes sooner, and - the **next** `git fetch` -- including the background maintenance `prefetch` task -- still performs the prefetch, hydrating the object cache shortly afterward. The option has no effect when the GVFS Protocol is not in use. ### Documentation `Documentation/scalar.adoc` documents `--[no-]prefetch`, making clear that it only affects the clone's initial fetch and that the prefetch data is still downloaded by the next fetch. ### Tests `t/t9210-scalar.sh` gains a test against the GVFS-enabled test server which asserts that: - a normal clone emits a `prefetch/since` trace event, - a `--no-prefetch` clone does not, - the persisted `core.gvfs` remains `150`, and - a subsequent `git fetch` performs the deferred prefetch.
Fetching a large set of missing objects through gvfs-helper performs each HTTP POST and index-pack operation sequentially. This leaves the client waiting on individual network transfers even when the server and local machine can support concurrent work. Introduce the parallel success-path mechanism. Use a mutex-protected queue to distribute full object batches across worker threads. Each worker owns a curl handle and streams each response into a fresh index-pack process. Serialize child startup while marking pipe descriptors close-on-exec so concurrent index-pack children cannot keep sibling pipes open. Keep OID formatting and result collection thread-local, and partition work into batches containing at least two objects because a single non-commit object can be returned loose instead of as a pack. This commit deliberately establishes the core worker and transfer mechanics first. The next commit completes authentication, throttling, fallback, retry, and concurrent pack installation behavior before tests exercise the new path. Helped-by: GPT-5.6 Sol Co-authored-by: Neil Kainga <t-neilkainga@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Neil Kainga <t-neilkainga@microsoft.com> Signed-off-by: Derrick Stolee <stolee@gmail.com>
Since f978f56 (odb: eagerly initialize alternates, 2026-08-17), config-only commands emit error-labelled diagnostics for unusable alternates even though those entries are ignored. An unset config key still returns the ordinary status 1, but VFS mistakes the accompanying diagnostics for a configuration failure and cannot recreate a deleted shared cache. Warnings keep these diagnostics visible without implying that ignoring an alternate is a command failure, and VFS already tolerates them. The message text and source rejection behavior remain unchanged. Assisted-by: GPT-6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The initial parallel POST path handles successful requests but does not yet match the sequential path when authentication, throttling, corrupt responses, or concurrent pack installation interfere with a request. Those differences can turn recoverable network failures into hard errors or allow sibling processes to manipulate the same pack paths. Classify HTTP and curl failures with the existing retry rules, refresh credentials outside worker threads, and preserve the cache, backup cache, and origin fallback order. Share response-header parsing with the sequential path so workers retain rate-limit telemetry while keeping soft-throttle state local to each worker. Coordinate Retry-After delays across workers without overflowing sleep intervals, and wait before starting index-pack. Serialize child setup and completion because finish_command() invalidates process-global path state. Limit the worker count to the number of queued object batches. Give each index-pack attempt unique pack and index paths, validate its reported pack hash, and retry corrupt or truncated responses. A complete final pack and index pair remains sufficient when another process wins the installation race. Group the per-attempt buffers behind one cleanup helper so success, retry, fallback, and failure paths release the same state. Helped-by: GPT-5.6 Sol Co-authored-by: Neil Kainga <t-neilkainga@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Neil Kainga <t-neilkainga@microsoft.com> Signed-off-by: Derrick Stolee <stolee@gmail.com>
A VS x64 build linked scalar successfully, then its post-build vcpkg.exe z-applocal invocation failed with "The process cannot access the file because it is being used by another process." MSBuild reported exit 32. https://github.com/microsoft/git/actions/runs/35200873703 In vcpkg 2026-07-27, the telemetry self-copy can open the tool's executable without sharing (src/vcpkg/base/files.cpp:3757-3832), outside the DLL deployment mutex. That can prevent concurrent launches with the same diagnostic and exit status, although the CI lock owner was not recorded. Avoid this source of contention by disabling unnecessary telemetry for MSBuild, retaining native app-local DLL deployment and four workers. Assisted-by: GPT-6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Exercise gvfs-helper POST requests with both one and four configured workers so the sequential and parallel paths must fetch identical object sets. Cover multiple batches, a final single-OID remainder, and duplicate requests while checking both installed objects and packfile counts. Require pthread support for parallel cases and use Trace2 assertions to prove that each test reaches its intended execution mode. Helped-by: GPT-5.6 Sol Co-authored-by: Neil Kainga <t-neilkainga@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Neil Kainga <t-neilkainga@microsoft.com> Signed-off-by: Derrick Stolee <stolee@gmail.com>
Cargo's MSVC builds need Microsoft's `link.exe` to take precedence. 41d1d14 (rust: fix linking binaries with cargo) assumes `/mingw64/bin`, so `/ucrt64/bin` can remain ahead of MSVC in `PATH`. Honor the active MinGW environment, including SDK setups that provide `MSYSTEM` rather than `MINGW_PREFIX`. Use the modern UCRT64 default when neither is set, while explicit `MSYSTEM=MINGW64` or `MINGW_PREFIX=/mingw64` settings continue to select the legacy toolchain. Assisted-by: GPT-6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Parallel requests need to preserve the sequential path's behavior for configuration boundaries, authentication, throttling, cache fallback, corrupt responses, and request headers. Extend the protocol test server with targeted failure modes. Verify that parallel POST refreshes authentication, honors Retry-After, falls back from cache 404 responses only when permitted, retries a one-time corrupt pack, and reports permanent corruption as an index-pack failure. Also cover absent and invalid thread configuration, cookie-enabled sequential fallback, configured headers, multiple participating workers, and a timeout-protected child-pipe stress case. Helped-by: GPT-5.6 Sol Co-authored-by: Neil Kainga <t-neilkainga@microsoft.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Neil Kainga <t-neilkainga@microsoft.com> Signed-off-by: Derrick Stolee <stolee@gmail.com>
CMake's x64 build definitions already select UCRT64, but the runtime fallback still assumes `/mingw64`. Match the existing defaults when `system_prefix()` cannot infer the prefix from the executable location. Normal discovery and explicit architecture definitions remain unchanged. Assisted-by: GPT-6 Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Improve full-clone performance by allowing `gvfs-helper post` to download object batches concurrently. The new `gvfs.postThreads` configuration defaults to 1, preserving the existing sequential behavior unless explicitly enabled. The series is organized into six reviewable commits: 1. Add the configuration surface. 2. Factor reusable curl-handle preparation. 3. Introduce the parallel POST success path. 4. Complete retry, authentication, fallback, throttling, and pack installation behavior. 5. Test sequential and parallel success paths. 6. Test failure handling and request-header parity. Each worker owns an independently prepared curl handle and streams responses into a dedicated `index-pack --stdin` child. Work is distributed through a mutex-protected queue, with the worker count capped by the number of object batches. Requests with configured cookies retain the established sequential path because libcurl cookie state cannot safely be shared by concurrently performing handles. The parallel path preserves the sequential HTTP policy for authentication refresh, transient errors, Retry-After, cache and backup-cache fallback, `--no-fallback`, configured headers, `X-Session-Id`, and `X-VSS-E2EID`. Sequential and parallel requests share response-header parsing, while soft-throttle state remains local to each worker. Child pipes are created and marked close-on-exec before spawning, and child setup and completion are serialized around process-global run-command state. Each `index-pack` attempt uses unique pack and index paths, validates its reported pack hash, retries corrupt or truncated responses, and tolerates another process winning installation of the same final pack. The focused `t5798-gvfs-helper-post-threads.sh` suite contains 22 tests covering configuration boundaries, sequential and parallel requests, multi-worker participation, singleton remainders, duplicate downloads, deadlock prevention, authentication, throttling, cache fallback, `--no-fallback`, corrupt packs, cookies, and configured headers. Parallel tests use pthread prerequisites and Trace2 assertions to prove the intended execution path. Neil Kainga diagnosed and tested the pipe-inheritance fix on a 1JS full clone with `gvfs.postThreads=8` and is credited throughout the series.
Matthew John Cheetham (mjcheetham)
approved these changes
Sep 23, 2026
Johannes Schindelin (dscho)
merged commit Sep 23, 2026
c81d6fd
into
vfs-2.56.0-rc2
167 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Range-diff relative to tentative/vfs-2.56.0-rc1
1: e8b6f68 = 1: 9379aac t: remove advice from some tests
2: a837ddc = 2: a3a6696 survey: calculate more stats on refs
3: d2d8b2b = 3: 5a214a6 survey: show some commits/trees/blobs histograms
4: 4a763a5 = 4: 3448f4c survey: add vector of largest objects for various scaling dimensions
5: 48f7678 = 5: 7f5623f survey: add pathname of blob or tree to large_item_vec
6: 84ee7a3 = 6: d792365 survey: add commit-oid to large_item detail
7: bac7b8a = 7: 609d189 fixup! ci(dockerized): do show the result of failing tests again
8: 679d30d = 8: 066a7b5 survey: add commit name-rev lookup to each large_item
9: 7ce6a12 = 9: c92da0d fixup! Add a GitHub workflow to verify that Git/Scalar work in Nano Server
10: a10d5f5 = 10: 6c32b4c survey: add --no-name-rev option
11: 91ae0a0 = 11: 49c68aa fixup! mingw: allow
git.exeto be used instead of the "Git wrapper"12: 2a72bc2 = 12: bc80ee7 sparse-index.c: fix use of index hashes in expand_index
13: 8545e8f = 13: 9957c08 survey: started TODO list at bottom of source file
14: c558d23 = 14: 501f636 fixup! Add an AGENTS.md file to help with AI-assisted debugging/development
15: 62dfe30 = 15: 00af8d1 t5300: confirm failure of git index-pack when non-idx suffix requested
16: 4b6a062 = 16: 8244a85 t1092: add test for untracked files and directories
17: 5d6b31e = 17: 200308c survey: expanded TODO list at the bottom of the source file
18: 3e3cda8 = 18: 2220bdb fixup! survey: turn into a thin shim over
git repo structure19: 21a20d7 = 19: b57764e index-pack: disable rev-index if index file has non .idx suffix
20: 6e71e20 = 20: dcc6873 survey: expanded TODO with more notes
21: b6e9a10 = 21: db73bb5 trace2: prefetch value of GIT_TRACE2_DST_DEBUG at startup
22: 4b3f05f = 22: 1228c43 reset --stdin: trim carriage return from the paths
23: 2315267 ! 23: 6d86dbe Identify microsoft/git via a distinct version suffix
24: 387d42e = 24: fd7d55c gvfs: ensure that the version is based on a GVFS tag
25: 8fe0318 = 25: e7e05a6 gvfs: add a GVFS-specific header file
26: 6bb6cea = 26: 2591c20 gvfs: add the core.gvfs config setting
27: 3104500 = 27: ad0ec9f gvfs: add the feature to skip writing the index' SHA-1
63: bc828ac = 28: 70a66f3 gvfs: add the feature that blobs may be missing
64: efe7aac = 29: d694564 gvfs: prevent files to be deleted outside the sparse checkout
65: 7cd8abe = 30: 82c6d2b gvfs: optionally skip reachability checks/upload pack during fetch
66: 9e059c1 = 31: 480ec32 gvfs: ensure all filters and EOL conversions are blocked
67: 936c3cb = 32: fd6c2f9 gvfs: allow "virtualizing" objects
68: 7078bf0 = 33: 1a0b292 Hydrate missing loose objects in check_and_freshen()
69: 52d65c3 = 34: 0bec9c1 sha1_file: when writing objects, skip the read_object_hook
70: 0db9709 = 35: 4a963ac gvfs: add global command pre and post hook procs
71: cca50d8 = 36: e88ea77 t0400: verify that the hook is called correctly from a subdirectory
72: dab4515 = 37: a915109 t0400: verify core.hooksPath is respected by pre-command
73: 379801e = 38: 95c2ea4 Pass PID of git process to hooks.
74: f27b308 = 39: 0776575 sparse-checkout: make sure to update files with a modify/delete conflict
75: 5f08216 = 40: 1189373 worktree: allow in Scalar repositories
76: e638b16 = 41: fb37987 sparse-checkout: avoid writing entries with the skip-worktree bit
77: 919aede = 42: 1d473ff Do not remove files outside the sparse-checkout
78: d4d2f19 = 43: d41acf8 send-pack: do not check for sha1 file when GVFS_MISSING_OK set
79: 14afb0c = 44: 7ec8755 gvfs: allow corrupt objects to be re-downloaded
80: df9d855 = 45: 6ca4180 cache-tree: remove use of strbuf_addf in update_one
81: d744a50 = 46: 78e28a9 gvfs: block unsupported commands when running in a GVFS repo
82: 5293057 = 47: 50dc39c gvfs: allow overriding core.gvfs
83: fe70f93 = 48: d9f471a BRANCHES.md: Add explanation of branches and using forks
84: e3dce25 = 49: c0336a6 Add virtual file system settings and hook proc
85: 155b7d1 = 50: 988bd50 virtualfilesystem: don't run the virtual file system hook if the index has been redirected
86: 71d3838 = 51: b9dc8e0 virtualfilesystem: check if directory is included
87: 3b7e478 = 52: 51ffe7c backwards-compatibility: support the post-indexchanged hook
88: 6aa05b5 = 53: 0c658dd gvfs: verify that the built-in FSMonitor is disabled
89: 32f6ed5 = 54: 99c1c0a wt-status: add trace2 data for sparse-checkout percentage
90: 9bfac18 = 55: 5e43e31 status: add status serialization mechanism
91: 193e7a2 = 56: 44c08a2 Teach ahead-behind and serialized status to play nicely together
92: 3ab1d75 = 57: a6fd408 status: serialize to path
93: 9be55c9 = 58: d0eafba status: reject deserialize in V2 and conflicts
94: 0b0ec59 = 59: c497222 serialize-status: serialize global and repo-local exclude file metadata
95: af8635a = 60: 20c3ac1 status: deserialization wait
96: 787969c = 61: 27ab58a status: deserialize with -uno does not print correct hint
97: f29d65e = 62: c93606e fsmonitor: check CE_FSMONITOR_VALID in ce_uptodate
98: a916773 = 63: 0479cb5 fsmonitor: add script for debugging and update script for tests
99: b9e929c = 64: b60e2e0 status: disable deserialize when verbose output requested.
100: 7503d99 = 65: d436dce t7524: add test for verbose status deserialzation
101: 5aa1c05 = 66: f009728 deserialize-status: silently fallback if we cannot read cache file
102: 115a64e = 67: b14125e gvfs:trace2:data: add trace2 tracing around read_object_process
103: ec1b027 = 68: ac8472b gvfs:trace2:data: status deserialization information
104: 6c3dfbd = 69: 92603b7 gvfs:trace2:data: status serialization
105: b5d3600 = 70: 1081120 gvfs:trace2:data: add vfs stats
106: 9ae932b = 71: c329d80 trace2: refactor setting process starting time
107: 3f1d7c1 = 72: 310b456 trace2:gvfs:experiment: report_tracking
109: f0e4207 = 73: f4de229 trace2:gvfs:experiment: read_cache: annotate thread usage in read-cache
111: dc929de = 74: e9274f4 trace2:gvfs:experiment: read-cache: time read/write of cache-tree extension
113: b407c07 = 75: 865c2fe trace2:gvfs:experiment: add region to apply_virtualfilesystem()
115: 6dfe362 = 76: d8b8e55 trace2:gvfs:experiment: add region around unpack_trees()
108: 8718e26 = 77: f342d73 git.c: add VFS enabled cmd blocking
117: 7554357 = 78: 98f6824 trace2:gvfs:experiment: add region to cache_tree_fully_valid()
110: be11956 = 79: 1f6b9c9 git.c: permit repack cmd in Scalar repos
119: 26176b8 = 80: 0556c3c trace2:gvfs:experiment: add unpack_entry() counter to unpack_trees() and report_tracking()
112: 491ddfa = 81: 3de6f10 git.c: permit fsck cmd in Scalar repos
120: f09b67d = 82: ee78215 trace2:gvfs:experiment: increase default event depth for unpack-tree data
114: 76b2053 = 83: b10c2ef git.c: permit prune cmd in Scalar repos
121: 65f6c35 = 84: 43baf0f trace2:gvfs:experiment: add data for check_updates() in unpack_trees()
116: af6ff28 = 85: e539d2c worktree: remove special case GVFS cmd blocking
122: 11ffcc8 = 86: 09ea369 Trace2:gvfs:experiment: capture more 'tracking' details
118: b51cffb = 87: 137c835 builtin/repack.c: emit warning when shared cache is present
123: 3fa557b = 88: e634502 credential: set trace2_child_class for credential manager children
124: bc332b6 = 89: 9940d89 sub-process: do not borrow cmd pointer from caller
125: 09086b7 = 90: c2fc078 sub-process: add subprocess_start_argv()
126: fa9f21e = 91: 68f3fe4 sha1-file: add function to update existing loose object cache
127: 502918c = 92: 49754d2 index-pack: avoid immediate object fetch while parsing packfile
128: fcb6c54 = 93: 1985059 gvfs-helper: create tool to fetch objects using the GVFS Protocol
129: 2db620a ! 94: f00f5f0 (which auto-squashed c5d6bc6) sha1-file: create shared-cache directory if it doesn't exist
131: 51f1386 = 95: f78cabb gvfs-helper: better handling of network errors
132: 7f4a505 = 96: 376220a gvfs-helper-client: properly update loose cache with fetched OID
133: aea7e33 = 97: e4f7f48 gvfs-helper: V2 robust retry and throttling
134: 6780db4 = 98: c612bae gvfs-helper: expose gvfs/objects GET and POST semantics
135: ca5a532 = 99: 3d4fe11 gvfs-helper: dramatically reduce progress noise
136: 669cda6 = 100: cf008d8 gvfs-helper: handle pack-file after single POST request
137: 57d89ba = 101: a1297ba test-gvfs-prococol, t5799: tests for gvfs-helper
138: d0bbcdd = 102: 5c7f6d0 gvfs-helper: move result-list construction into install functions
139: b6b3d0f = 103: 06ae72f t5799: add support for POST to return either a loose object or packfile
140: 085879c = 104: 773b79d t5799: cleanup wc-l and grep-c lines
141: 1761118 = 105: a80c966 gvfs-helper: verify loose objects after write
142: 9e4d6d2 = 106: 1b84a7c t7599: create corrupt blob test
143: a366684 = 107: 5103ca3 gvfs-helper: add prefetch support
144: 9081419 = 108: 398a98a gvfs-helper: add prefetch .keep file for last packfile
145: 3525dc8 = 109: ed445c7 gvfs-helper: do one read in my_copy_fd_len_tail()
146: c49e061 = 110: 5a2160d gvfs-helper: move content-type warning for prefetch packs
147: da218cf = 111: c4512c7 fetch: use gvfs-helper prefetch under config
148: 5a0c9ce = 112: da74952 gvfs-helper: better support for concurrent packfile fetches
149: d35d1ad = 113: 65bcb62 remote-curl: do not call fetch-pack when using gvfs-helper
150: 8a3a478 = 114: 4ac394c fetch: reprepare packs before checking connectivity
151: e6abb7b = 115: 3124a19 gvfs-helper: retry when creating temp files
152: 9074f57 = 116: 23bc195 sparse: avoid warnings about known cURL issues in gvfs-helper.c
159: 15955cf = 117: e487418 maintenance: care about gvfs.sharedCache config
161: cb7ad0b = 118: 8299e93 unpack-trees:virtualfilesystem: Improve efficiency of clear_ce_flags
167: e083895 = 119: dbc1f92 Disable the
monitor-componentsworkflow in msft-git169: 0c2b041 = 120: 2e6f7ca .github: enable windows builds on microsoft fork
170: a6fc155 = 121: a1dc4ee .github/actions/akv-secret: add action to get secrets
171: 1cb5171 = 122: 94c21fa release: create initial Windows installer build workflow
173: 3b76db4 = 123: 770c9f2 help: special-case HOST_CPU
universal175: 0f618ed = 124: e0fe67c release: add Mac OSX installer build
177: d52f6fb = 125: 0256aea release: build unsigned Ubuntu .deb package
153: ae1b721 = 126: de0c8d2 gvfs-helper: add --max-retries to prefetch verb
179: 3abdd32 = 127: d5e0466 release: add signing step for .deb package
154: 550d785 = 128: 6027dd2 t5799: add tests to detect corrupt pack/idx files in prefetch
181: a4ca71e = 129: 139b0fe release: create draft GitHub release with packages & installers
155: 824accb = 130: 36d7a30 gvfs-helper: ignore .idx files in prefetch multi-part responses
183: dd44bd0 = 131: 4d09afc build-git-installers: publish gpg public key
156: 1c06ba8 = 132: 7554a9a t5799: explicitly test gvfs-helper --fallback and --no-fallback
185: ad19277 = 133: ccfe9a8 release: continue pestering until user upgrades
157: 8f1f114 = 134: f0582ab gvfs-helper: don't fallback with new config
187: 6721b29 = 135: 73901ea dist: archive HEAD instead of HEAD^{tree}
158: cf79810 = 136: b6e2b8a test-gvfs-protocol: add cache_http_503 to mayhem
189: b280761 = 137: 5726a9e release: include GIT_BUILT_FROM_COMMIT in MacOS build
160: b5cab59 = 138: 7dbb617 t5799: add unit tests for new
gvfs.fallbackconfig setting191: fa4f8aa = 139: 374658f release: remove the obsolete GitHub installer workflow
28: dad67c0 = 140: 9bf7ec5 scalar: set the config write-lock timeout to 150ms
29: 0e97b91 = 141: 4cece70 scalar: set the config write-lock timeout to 150ms
30: 6e5b9ce = 142: ccd1822 scalar: upgrade the config lock timeout setting automagically
162: db7bf8e = 143: bc5ee0e update-microsoft-git: create barebones builtin
31: e3d9c2c = 144: 45e6e6e config: (handle and) warn about deprecated lock timeout setting
163: 3d22821 = 145: 304b867 update-microsoft-git: Windows implementation
32: c6dcc7d = 146: 45a0b08 scalar: add docs from microsoft/scalar
164: 236dd62 = 147: a5f0546 update-microsoft-git: use brew on macOS
165: 87eff26 = 148: 195c94f .github: reinstate ISSUE_TEMPLATE.md for microsoft/git
33: 48f662a = 149: 40b79c9 scalar (Windows): use forward slashes as directory separators
166: 0ca8687 = 150: 6199e21 .github: update PULL_REQUEST_TEMPLATE.md
34: c836201 = 151: a22b2ac scalar: add retry logic to run_git()
168: 3d8b726 = 152: d703e7b Adjust README.md for microsoft/git
35: 8eeb0de = 153: 5a6d8aa scalar: support the
configcommand for backwards compatibility172: 9959362 = 154: 9d123db scalar: implement a minimal JSON parser
174: 2afa625 = 155: 041eda1 scalar clone: support GVFS-enabled remote repositories
176: bc5eb4b = 156: 0845a2a test-gvfs-protocol: also serve smart protocol
178: 284e0a0 = 157: ba78067 gvfs-helper: add the
endpointcommand180: 1f84a71 = 158: 4c3a323 dir_inside_of(): handle directory separators correctly
182: e629027 = 159: d8cea53 scalar: disable authentication in unattended mode
184: 6a60f66 = 160: fdc5074 abspath: make strip_last_path_component() global
186: 59077f5 = 161: 91d162e scalar: do initialize
gvfs.sharedCache188: 9531cdf = 162: ac8efd7 scalar diagnose: include shared cache info
190: 04149c4 = 163: 98d8206 scalar: only try GVFS protocol on https:// URLs
195: e4e0016 = 164: 745ea26 scalar: verify that we can use a GVFS-enabled repository
197: 10ebb67 = 165: b8bfc94 scalar: add the
cache-servercommand198: 161442e = 166: ded06e2 scalar: add a test toggle to skip accessing the vsts/info endpoint
199: 70e8e5d = 167: 6e6102b scalar: adjust documentation to the microsoft/git fork
201: df33d6d = 168: f622b16 scalar: enable untracked cache unconditionally
192: ac5e537 = 169: 437dd9e add/rm: allow adding sparse entries when virtual
193: 89e87c5 = 170: c1cd1e9 sparse-checkout: add config to disable deleting dirs
194: ecac8e8 = 171: b8c4907 diff: ignore sparse paths in diffstat
196: 3488094 = 172: 6399fd4 repo-settings: enable sparse index by default
36: a9ee7c4 = 173: 5c5749e TO-UPSTREAM: sequencer: avoid progress when stderr is redirected
200: bae5811 = 174: ff97e0d TO-CHECK: t1092: use quiet mode for rebase tests
203: dbef07a = 175: 3ad5e6b scalar: parse
clone --no-fetch-commits-and-treesfor backwards compatibility202: 75d5414 = 176: 2c2f23b reset: fix mixed reset when using virtual filesystem
205: e53877a = 177: 3f5f933 scalar: make GVFS Protocol a forced choice
204: 4e56187 = 178: 57d01e4 diff(sparse-index): verify with partially-sparse
207: fab48c9 = 179: 185c9b9 scalar: work around GVFS Protocol HTTP/2 failures
206: 32e5af4 = 180: 9452c72 stash: expand testing for
git stash -u209: f70640d = 181: bd1c66e gvfs-helper-client: clean up server process(es)
208: f963cdc = 182: d702dee sparse-index: add ensure_full_index_with_reason()
211: 42890de = 183: 3525abe scalar diagnose: accommodate Scalar's Functional Tests
210: cedaeec = 184: 63a372c treewide: add reasons for expanding index
213: 555d92e = 185: 173fbe8 ci: run Scalar's Functional Tests
212: 4a598f6 = 186: 1a82f14 treewide: custom reasons for expanding index
215: e79d611 = 187: 78131bd scalar: upgrade to newest FSMonitor config setting
214: 7a1ee60 = 188: 5344e5f sparse-index: add macro for unaudited expansions
216: f13ff22 = 189: 9a468b7 Docs: update sparse index plan with logging
217: 118b6bb = 190: ebccc52 sparse-index: log failure to clear skip-worktree
218: 713abdb = 191: 3ae6c7a stash: use -f in checkout-index child process
219: ffa770d = 192: b99e79c sparse-index: do not copy hashtables during expansion
220: b74aa97 = 193: 39962f1 TO-UPSTREAM: sub-process: avoid leaking
cmd221: bf9f191 = 194: f43dc34 remote-curl: release filter options before re-setting them
222: 84b8512 = 195: 99f1c46 transport: release object filter options
223: 9acea34 = 196: 7717442 push: don't reuse deltas with path walk
224: 5d6b49f = 197: 54df6d5 maintenance: add cache-local-objects maintenance task
225: 6dab639 = 198: e928dde scalar.c: add cache-local-objects task
226: 0cc3de9 = 199: 7eb9335 hooks: add custom post-command hook config
37: 8413b20 = 200: 350ead2 cat_one_file(): make it easy to see that the
sizevariable is initialized227: 54006fe = 201: 13df2a1 TO-UPSTREAM: Docs: fix asciidoc failures from short delimiters
38: 2a33af0 = 202: 6356600 fsck: avoid using an uninitialized variable
228: 699c357 = 203: 0ca1364 hooks: make hook logic memory-leak free
41: 0dcf0ca = 204: ce86290 revision: defensive programming
39: 043d525 = 205: e05a1ac load_revindex_from_disk(): avoid accessing uninitialized data
229: 7eba3af = 206: 3519feb t0401: test post-command for alias, version, typo
42: 0d6ccdd = 207: 6e52191 get_parent(): defensive programming
40: 975532c = 208: 05ca572 load_pack_mtimes_file(): avoid accessing uninitialized data
230: 8558aa6 = 209: e6ec9ec hooks: better handle config without gitdir
43: 80ee9af = 210: 5425810 fetch-pack: defensive programming
44: 3991a05 = 211: 5477bb3 codeql: run static analysis as part of CI builds
45: 2625274 = 212: 7dca882 unparse_commit(): defensive programming
46: bebfeea = 213: c62e391 codeql: publish the sarif file as build artifact
47: 8c0cfd6 = 214: f090180 verify_commit_graph(): defensive programming
48: 68098e0 = 215: 1496405 codeql: disable a couple of non-critical queries for now
49: 1002a1e = 216: 892800a stash: defensive programming
50: a728598 = 217: 33f0a8f date: help CodeQL understand that there are no leap-year issues here
51: 8d99b7e = 218: c1f3602 stash: defensive programming
52: 2c56230 = 219: fe93246 help: help CodeQL understand that consuming envvars is okay here
53: a591bf1 = 220: bc1b052 push: defensive programming
54: f539aa9 = 221: 8587b48 ctype: help CodeQL understand that
sane_istest()does not access array past end55: 63c78c3 = 222: 721be97 test-tool repository: check return value of
lookup_commit()56: d4d2bbb = 223: 370ed28 fetch: defensive programming
57: 4647696 = 224: 2aa788c ctype: accommodate for CodeQL misinterpreting the
zinmallocz()58: 8119da8 = 225: 1ceab82 shallow: handle missing shallow commits gracefully
59: b8d6506 = 226: 51b2566 inherit_tracking(): defensive programming
60: c5c7510 = 227: 8ba05a9 strbuf_read: help with CodeQL misunderstanding that
strbuf_read()does NUL-terminate correctly61: 7f82c2a = 228: f1c91aa commit-graph: suppress warning about using a stale stack addresses
62: 264244e = 229: 60150d8 codeql: also check JavaScript code
130: c5d6bc6 < -: ----------- fixup! sha1-file: create shared-cache directory if it doesn't exist
231: c77fe05 = 230: 4536990 scalar: add run_git_argv
232: 7d67fa7 = 231: a7dad14 scalar: add --ref-format option to scalar clone
233: 677b777 = 232: ab3a54d gvfs-helper: skip collision check for loose objects
234: 9a5a7d8 = 233: 17475dd gvfs-helper: emit advice on transient errors
235: 6edf57e = 234: 9e70516 gvfs-helper: avoid collision check for packfiles
236: 25778e2 = 235: c20f6d5 t5799: update cache-server methods for multiple instances
237: c8341af = 236: 6273fc9 gvfs-helper: override cache server for prefetch
238: d8b669f = 237: 7327807 gvfs-helper: override cache server for get
239: 2296011 = 238: 1338aca gvfs-helper: override cache server for post
240: 3a717d1 = 239: 83eb1e6 t5799: add test for all verb-specific cache-servers together
241: 22f9441 = 240: 6f0f923 lib-gvfs-helper: create helper script for protocol tests
242: 8e807f3 = 241: ffcd3cf t579*: split t5799 into several parts
243: 8f24271 = 242: 51d9c4c scalar: add ---cache-server-url options
244: d8ae2cf = 243: ad6b63a Restore previous errno after post command hook
245: 876afc3 = 244: a3a424b t9210: differentiate origin and cache servers
246: e17bbfd = 245: 457a1e1 unpack-trees: skip lstats for deleted VFS entries in checkout
247: 8073299 = 246: fc1199e worktree: conditionally allow worktree on VFS-enabled repos
249: 1f725d7 = 247: 7aaf1bd gvfs-helper: send X-Session-Id headers
248: fce704b = 248: 96c217c gvfs-helper: create shared object cache if missing
250: 204ccf2 = 249: 7467920 gvfs: add gvfs.sessionKey config
251: a044a27 = 250: a48ce17 gvfs: clear DIE_IF_CORRUPT in streaming incore fallback
252: 334fb47 = 251: 4b047ac worktree remove: use GVFS_SUPPORTS_WORKTREES for skip-clean-check gate
253: ef7f7fd = 252: 588e91e ci: add new VFS for Git functional tests workflow
254: 08cd50f = 253: 3ef7d12 azure-pipelines: add stub release pipeline for Azure
255: 4793e5f = 254: 5289332 diff: add renameThreshold configuration option
257: f2e175d = 255: 75ea3dd blame: add blame.renames, blame.renameThreshold, blame.renameLimit
256: 50951a5 = 256: 80edcbc gvfs-helper: separate packfile extraction from indexing
258: e20ff86 = 257: 5d5dcb4 gvfs-helper: run prefetch index-pack in parallel
259: 244d595 = 258: 184a4d6 gvfs-helper: add gvfs.prefetchThreads config for parallel prefetch
260: 1631c47 = 259: f1da780 azure-pipelines: add ESRP code signing
261: eb515d7 = 260: 60d911e azure-pipelines: allow overriding Git version
262: cff8a32 = 261: c54863b azure-pipelines: build, sign and stage the Linux Debian package
263: bac85b6 = 262: 6c849d0 azure-pipelines: add signed macOS ARM64 releases
264: de16895 = 263: 376fb65 azure-pipelines: build, sign and stage the Windows installer
265: 3051db2 = 264: c6795be azure-pipelines: enable on tag push, default ESRP and GitHub release on
266: 36f0c21 = 265: e7f6d3b release: binskim for Windows
267: e26f975 = 266: 6dce414 release: suppress unfixable binskim findings
268: 1ac3713 = 267: 9a69fe5 binskim: add baseline
269: 7b3aa78 = 268: 9a110d6 checkout: preserve skip-worktree for virtual filesystem paths
270: 428f04e = 269: 3109aff ci(vfs): install the GCC-compatible Rust target before building
271: f0a9340 = 270: b602ad3 release-homebrew: add a hand-run script to replace the workflow
272: 6f360f9 = 271: 40b58bb release-vfsforgit: add hand-run script to supersede the workflow
273: 5a089ba = 272: f097bbe .github: add release-winget.sh to open winget-pkgs PR
274: 9b99ba8 = 273: 1902c40 trace2: tolerate failed timestamp formatting
275: 846d5de = 274: 3760c89 reset --mixed: clear skip-worktree for all changed entries in VFS mode
276: 36faa37 = 275: 8c65397 send-pack: add gvfs.negativeRefCheck to skip missing negatives
277: 74d7f80 = 276: 1578839 odb: scan all sources' packfiles before loose objects
278: 6fd9369 = 277: f2235f4 scalar: add --[no-]prefetch option
279: a8aab29 = 278: f4cc03f scalar: request for commit via POST
280: 919a530 = 279: 87f7201 odb: warn when ignoring unusable alternates
281: 7bf7e90 = 280: 78da126 ci: avoid vcpkg telemetry contention during MSBuild
282: a3273f7 = 281: 2156aaa rust: honor the active MinGW prefix when invoking Cargo
283: 92bfd44 = 282: 07147aa cmake: default the Windows runtime prefix to UCRT64
284: 5ae7fad = 283: aec46ac gvfs-helper: add gvfs.postThreads config option
285: 2b87ce6 = 284: b6bbc22 http: factor reusable curl handle preparation
286: dc15f86 = 285: b978a96 gvfs-helper: parallelize POST object requests
287: e86ce06 = 286: 0e1942f gvfs-helper: preserve POST failure handling in parallel mode
288: bc00162 = 287: 84b71a5 t5798: test parallel POST object requests
289: eefe24c = 288: fa0381c t5798: test parallel POST failure handling