Rebase to Git for Windows 2.56.0 - #995
Merged
Merged
Conversation
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Jeff Hostetler <jeffhostetler@github.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>
Add data for the number of files created/overwritten and deleted during the checkout. Give proper category name to all events in unpack-trees.c and eliminate "exp". This is modified slightly from the original version due to interactions with 26f924d (unpack-trees: exit check_updates() early if updates are not wanted, 2020-01-07). Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Derrick Stolee <dstolee@microsoft.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>
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>
Update tracing around report_tracking() to use 'tracking' category rather than 'exp' category. Add ahead/behind results from stat_tracking_info(). Signed-off-by: Jeff Hostetler <jeffhost@microsoft.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>
By default, Git fails immediately when locking a config file for writing fails due to an existing lock. With this change, Scalar-registered repositories will fall back to trying a couple times within a 150ms timeout. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Add a new JavaScript GitHub Action to download secrets from Azure Key Vault using the `az` CLI, mask the secret values, and store them as: * outputs, * environment variables, or * files; Values are all masked for safe consumption by other steps in a workflow. Callers of this action can optionally perform base64 decoding of secret values using the syntax: `INPUT base64> OUTPUT`. It is assumed that the `az login` command has already been run prior to this action being invoked. Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
By default, Git fails immediately when locking a config file for writing fails due to an existing lock. With this change, Scalar-registered repositories will fall back to trying a couple times within a 150ms timeout. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Add a manual-only GitHub Actions workflow for building the Windows installer (x86_64 plus portable Git), driven via `workflow_dispatch:`. The production release path for the official microsoft/git installers lives in .azure-pipelines/release.yml; this workflow is kept around as a fallback so the Windows installer can still be produced on demand for debugging or comparison. The build steps are pinned to `windows-2019` (rather than `windows-latest`) to ensure the correct Visual Studio version is used (verified in the pipeline via `type -p mspdb140.dll`), and the SDK used is the `full` flavor rather than `build-installers` due to a known (but not-yet-fixed) issue downloading the `build-installers` flavor with the `git-for-windows/setup-git-for-windows-sdk` Action. There is no code-signing certificate available to this workflow, so the artifacts it produces are unsigned and must not be published as releases; they are useful only for build-time debugging. Signed-off-by: Victoria Dye <vdye@github.com> Assisted-by: Claude Opus 4.7 Co-authored-by: Matthew John Cheetham <mjcheetham@outlook.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
In Git v2.56.0, a different name was chosen for that setting, and also a different default value. Let's automagically upgrade the name of the config setting, if present. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
When building Git as a universal binary on macOS, the binary supports more than one target architecture. This is a bit of a problem for the `HOST_CPU` setting that is woefully unprepared for such a situation, as it wants to show architecture hard-coded at build time. In preparation for releasing universal builds, work around this by special-casing `universal` and replacing it at run-time with the known values `x86_64` or `arm64`. Signed-off-by: Jeff Hostetler <jeffhostetler@github.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit reintroduces the 'core.configWriteLockTimeoutMS' config setting (originally added in 6333d1a (git_config_set_multivar_in_file_gently(): add a lock timeout, 2021-05-18) as part of Microsoft v2.32.0). Upstream, this setting was superseded by the `core.configLockTimeout` setting that was added in df67d73 (config: retry acquiring config.lock, configurable via core.configLockTimeout, 2026-05-17). However, several applications (e.g., 'scalar') utilize the original config setting, so it should be preserved for a deprecation period before complete removal: Additionally, for this deprecation period, advise users to switch to using 'core.configLockTimeout' to specify their preferred timeout. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
- include `scalar` - build signed .dmg & .pkg for target OS version 10.6 - upload artifacts to workflow Co-authored-by: Lessley Dennington <ldennington@github.com>
These docs have been altered to fit the version implemented in C within microsoft/git. This means in particular that the advanced.md file no longer applied at all. Some other areas were removed or significantly edited. Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Allow concurrent `scalar register` and `scalar unregister` calls to be more collaborative when trying to lock the global Git config at the very same time. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
- 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>
Adding the extra documentation from the Scalar project. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
- 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>
Git traditionally uses those, not backslashes, ever. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
- 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>
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 29, 2026
Matthew John Cheetham (mjcheetham)
left a comment
Member
There was a problem hiding this comment.
Nice clean range-diff! ❤️
Johannes Schindelin (dscho)
merged commit Sep 29, 2026
0faae01
into
vfs-2.56.0
391 of 394 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 vfs-2.56.0-rc2
12: bc80ee7 = 1: 7463336 sparse-index.c: fix use of index hashes in expand_index
15: 00af8d1 = 2: 7173c08 t5300: confirm failure of git index-pack when non-idx suffix requested
1: 9379aac = 3: 3727b2a t: remove advice from some tests
16: 8244a85 = 4: b3ac5b5 t1092: add test for untracked files and directories
19: b57764e = 5: e091dbc index-pack: disable rev-index if index file has non .idx suffix
21: db73bb5 = 6: b3b5b7b trace2: prefetch value of GIT_TRACE2_DST_DEBUG at startup
2: a3a6696 = 7: cc2f872 survey: calculate more stats on refs
3: 5a214a6 = 8: 8bd6b64 survey: show some commits/trees/blobs histograms
4: 3448f4c = 9: 73f3976 survey: add vector of largest objects for various scaling dimensions
5: 7f5623f = 10: 1ac52ea survey: add pathname of blob or tree to large_item_vec
6: d792365 = 11: ee2e352 survey: add commit-oid to large_item detail
7: 609d189 = 12: 6640dfe fixup! ci(dockerized): do show the result of failing tests again
8: 066a7b5 = 13: 86a64df survey: add commit name-rev lookup to each large_item
9: c92da0d = 14: 73068c4 fixup! Add a GitHub workflow to verify that Git/Scalar work in Nano Server
10: 6c32b4c = 15: 13d5b1c survey: add --no-name-rev option
11: 49c68aa = 16: a1f4042 fixup! mingw: allow
git.exeto be used instead of the "Git wrapper"13: 9957c08 = 17: c94cd88 survey: started TODO list at bottom of source file
14: 501f636 = 18: 2528646 fixup! Add an AGENTS.md file to help with AI-assisted debugging/development
17: 200308c = 19: 400a523 survey: expanded TODO list at the bottom of the source file
18: 2220bdb = 20: 5ffe6d3 fixup! survey: turn into a thin shim over
git repo structure20: dcc6873 = 21: 09c0572 survey: expanded TODO with more notes
22: 1228c43 = 22: 52b69ed reset --stdin: trim carriage return from the paths
23: 6d86dbe ! 23: 0d55edb Identify microsoft/git via a distinct version suffix
24: fd7d55c = 24: de76f0c gvfs: ensure that the version is based on a GVFS tag
25: e7e05a6 = 25: b890d07 gvfs: add a GVFS-specific header file
26: 2591c20 = 26: 2f41fb2 gvfs: add the core.gvfs config setting
27: ad0ec9f = 27: 6217409 gvfs: add the feature to skip writing the index' SHA-1
28: 70a66f3 = 28: 5ba0f63 gvfs: add the feature that blobs may be missing
29: d694564 = 29: 97405b9 gvfs: prevent files to be deleted outside the sparse checkout
30: 82c6d2b = 30: 7e1bc9f gvfs: optionally skip reachability checks/upload pack during fetch
31: 480ec32 = 31: f23ba9b gvfs: ensure all filters and EOL conversions are blocked
32: fd6c2f9 = 32: 5708ab7 gvfs: allow "virtualizing" objects
33: 1a0b292 = 33: 749f93c Hydrate missing loose objects in check_and_freshen()
34: 0bec9c1 = 34: 436ff0c sha1_file: when writing objects, skip the read_object_hook
35: 4a963ac = 35: 4d42f02 gvfs: add global command pre and post hook procs
36: e88ea77 = 36: 2c51a69 t0400: verify that the hook is called correctly from a subdirectory
37: a915109 = 37: 60faed1 t0400: verify core.hooksPath is respected by pre-command
38: 95c2ea4 = 38: 9eafa0c Pass PID of git process to hooks.
39: 0776575 = 39: 2be09c3 sparse-checkout: make sure to update files with a modify/delete conflict
40: 1189373 = 40: 07de674 worktree: allow in Scalar repositories
41: fb37987 = 41: 6949d44 sparse-checkout: avoid writing entries with the skip-worktree bit
42: 1d473ff = 42: 25409b3 Do not remove files outside the sparse-checkout
43: d41acf8 = 43: 393b7e5 send-pack: do not check for sha1 file when GVFS_MISSING_OK set
44: 7ec8755 = 44: 0b03cf9 gvfs: allow corrupt objects to be re-downloaded
45: 6ca4180 = 45: 47261c8 cache-tree: remove use of strbuf_addf in update_one
46: 78e28a9 = 46: 1eab9cc gvfs: block unsupported commands when running in a GVFS repo
47: 50dc39c = 47: 610b815 gvfs: allow overriding core.gvfs
48: d9f471a = 48: 27ca657 BRANCHES.md: Add explanation of branches and using forks
49: c0336a6 = 49: 6121fd2 Add virtual file system settings and hook proc
50: 988bd50 = 50: 3e9f877 virtualfilesystem: don't run the virtual file system hook if the index has been redirected
51: b9dc8e0 = 51: 80789bc virtualfilesystem: check if directory is included
52: 51ffe7c = 52: 2e005dd backwards-compatibility: support the post-indexchanged hook
53: 0c658dd = 53: e782eeb gvfs: verify that the built-in FSMonitor is disabled
54: 99c1c0a = 54: efec1e1 wt-status: add trace2 data for sparse-checkout percentage
55: 5e43e31 = 55: 56de860 status: add status serialization mechanism
56: 44c08a2 = 56: 1166e08 Teach ahead-behind and serialized status to play nicely together
57: a6fd408 = 57: 7ec6793 status: serialize to path
58: d0eafba = 58: b9e45cd status: reject deserialize in V2 and conflicts
59: c497222 = 59: 106e70c serialize-status: serialize global and repo-local exclude file metadata
60: 20c3ac1 = 60: f6d1c80 status: deserialization wait
61: 27ab58a = 61: 6be2a1b status: deserialize with -uno does not print correct hint
62: c93606e = 62: 00de60d fsmonitor: check CE_FSMONITOR_VALID in ce_uptodate
63: 0479cb5 = 63: 8718ab1 fsmonitor: add script for debugging and update script for tests
64: b60e2e0 = 64: 57d2936 status: disable deserialize when verbose output requested.
77: f342d73 = 65: 5cee6c2 git.c: add VFS enabled cmd blocking
65: d436dce = 66: f460e38 t7524: add test for verbose status deserialzation
79: 1f6b9c9 = 67: c93a00b git.c: permit repack cmd in Scalar repos
66: f009728 = 68: da3ee38 deserialize-status: silently fallback if we cannot read cache file
81: 3de6f10 = 69: 8d1f143 git.c: permit fsck cmd in Scalar repos
67: b14125e = 70: 55566bb gvfs:trace2:data: add trace2 tracing around read_object_process
83: b10c2ef = 71: fd9bb35 git.c: permit prune cmd in Scalar repos
68: ac8472b = 72: 450c001 gvfs:trace2:data: status deserialization information
85: e539d2c = 73: 3069d1e worktree: remove special case GVFS cmd blocking
69: 92603b7 = 74: 87eb2f9 gvfs:trace2:data: status serialization
87: 137c835 = 75: 5d1a9ef builtin/repack.c: emit warning when shared cache is present
70: 1081120 = 76: 7d2a9aa gvfs:trace2:data: add vfs stats
71: c329d80 = 77: 625a19d trace2: refactor setting process starting time
72: 310b456 = 78: a09b3f4 trace2:gvfs:experiment: report_tracking
73: f4de229 = 79: e949913 trace2:gvfs:experiment: read_cache: annotate thread usage in read-cache
74: e9274f4 = 80: 89816ef trace2:gvfs:experiment: read-cache: time read/write of cache-tree extension
75: 865c2fe = 81: 7216209 trace2:gvfs:experiment: add region to apply_virtualfilesystem()
76: d8b8e55 = 82: 00d4086 trace2:gvfs:experiment: add region around unpack_trees()
78: 98f6824 = 83: d02b4c9 trace2:gvfs:experiment: add region to cache_tree_fully_valid()
80: 0556c3c = 84: 866c6fc trace2:gvfs:experiment: add unpack_entry() counter to unpack_trees() and report_tracking()
82: ee78215 = 85: 75e48bf trace2:gvfs:experiment: increase default event depth for unpack-tree data
84: 43baf0f = 86: ab3ce37 trace2:gvfs:experiment: add data for check_updates() in unpack_trees()
86: 09ea369 = 87: 74946f0 Trace2:gvfs:experiment: capture more 'tracking' details
88: e634502 = 88: 9c6b56c credential: set trace2_child_class for credential manager children
89: 9940d89 = 89: 9b39a31 sub-process: do not borrow cmd pointer from caller
90: c2fc078 = 90: 2ebe773 sub-process: add subprocess_start_argv()
91: 68f3fe4 = 91: d236ac5 sha1-file: add function to update existing loose object cache
92: 49754d2 = 92: 540f465 index-pack: avoid immediate object fetch while parsing packfile
93: 1985059 = 93: 07a540e gvfs-helper: create tool to fetch objects using the GVFS Protocol
94: f00f5f0 = 94: e2ac4d7 sha1-file: create shared-cache directory if it doesn't exist
95: f78cabb = 95: d24e3cd gvfs-helper: better handling of network errors
96: 376220a = 96: 51c73ca gvfs-helper-client: properly update loose cache with fetched OID
97: e4f7f48 = 97: c234821 gvfs-helper: V2 robust retry and throttling
98: c612bae = 98: 8b90b17 gvfs-helper: expose gvfs/objects GET and POST semantics
99: 3d4fe11 = 99: f892b14 gvfs-helper: dramatically reduce progress noise
100: cf008d8 = 100: 646c7e1 gvfs-helper: handle pack-file after single POST request
101: a1297ba = 101: 38e8077 test-gvfs-prococol, t5799: tests for gvfs-helper
102: 5c7f6d0 = 102: aa960f4 gvfs-helper: move result-list construction into install functions
103: 06ae72f = 103: d027df4 t5799: add support for POST to return either a loose object or packfile
104: 773b79d = 104: 630809f t5799: cleanup wc-l and grep-c lines
105: a80c966 = 105: e0359c5 gvfs-helper: verify loose objects after write
106: 1b84a7c = 106: 7556764 t7599: create corrupt blob test
107: 5103ca3 = 107: 7201cbd gvfs-helper: add prefetch support
108: 398a98a = 108: 81062ec gvfs-helper: add prefetch .keep file for last packfile
109: ed445c7 = 109: 4420522 gvfs-helper: do one read in my_copy_fd_len_tail()
110: 5a2160d = 110: c8165c3 gvfs-helper: move content-type warning for prefetch packs
111: c4512c7 = 111: af053c6 fetch: use gvfs-helper prefetch under config
112: da74952 = 112: 637a7cb gvfs-helper: better support for concurrent packfile fetches
113: 65bcb62 = 113: 8eb72a3 remote-curl: do not call fetch-pack when using gvfs-helper
114: 4ac394c = 114: 6da2653 fetch: reprepare packs before checking connectivity
115: 3124a19 = 115: bec0553 gvfs-helper: retry when creating temp files
116: 23bc195 = 116: acf2d9e sparse: avoid warnings about known cURL issues in gvfs-helper.c
126: de0c8d2 = 117: fd4d860 gvfs-helper: add --max-retries to prefetch verb
128: 6027dd2 = 118: 7fe5232 t5799: add tests to detect corrupt pack/idx files in prefetch
130: 36d7a30 = 119: 10db8bd gvfs-helper: ignore .idx files in prefetch multi-part responses
132: 7554a9a = 120: e7b8d00 t5799: explicitly test gvfs-helper --fallback and --no-fallback
134: f0582ab = 121: 5dd772c gvfs-helper: don't fallback with new config
117: e487418 = 122: c838597 maintenance: care about gvfs.sharedCache config
118: 8299e93 = 123: 219ebba unpack-trees:virtualfilesystem: Improve efficiency of clear_ce_flags
119: dbc1f92 = 124: f3f0e5b Disable the
monitor-componentsworkflow in msft-git120: 2e6f7ca = 125: de6f508 .github: enable windows builds on microsoft fork
121: a1dc4ee = 126: 1f075cf .github/actions/akv-secret: add action to get secrets
122: 94c21fa = 127: 6b1da47 release: create initial Windows installer build workflow
123: 770c9f2 = 128: d4bf00e help: special-case HOST_CPU
universal140: 9bf7ec5 = 129: a5d20e9 scalar: set the config write-lock timeout to 150ms
124: e0fe67c = 130: 497191f release: add Mac OSX installer build
141: 4cece70 = 131: c5787fb scalar: set the config write-lock timeout to 150ms
125: 0256aea = 132: 9b95aaf release: build unsigned Ubuntu .deb package
142: ccd1822 = 133: 3b168a0 scalar: upgrade the config lock timeout setting automagically
143: bc5ee0e = 134: 1fcec3b update-microsoft-git: create barebones builtin
127: d5e0466 = 135: d07d812 release: add signing step for .deb package
144: 45e6e6e = 136: 870a629 config: (handle and) warn about deprecated lock timeout setting
145: 304b867 = 137: 36cf2f7 update-microsoft-git: Windows implementation
129: 139b0fe = 138: cbdcbc8 release: create draft GitHub release with packages & installers
146: 45a0b08 = 139: 5c9d88a scalar: add docs from microsoft/scalar
147: a5f0546 = 140: 57863d3 update-microsoft-git: use brew on macOS
131: 4d09afc = 141: c0a3a17 build-git-installers: publish gpg public key
148: 195c94f = 142: ae9b78c .github: reinstate ISSUE_TEMPLATE.md for microsoft/git
133: ccfe9a8 = 143: 459064f release: continue pestering until user upgrades
149: 40b79c9 = 144: 5367252 scalar (Windows): use forward slashes as directory separators
150: 6199e21 = 145: f9ce800 .github: update PULL_REQUEST_TEMPLATE.md
135: 73901ea = 146: fb2e14d dist: archive HEAD instead of HEAD^{tree}
151: a22b2ac = 147: 22a7966 scalar: add retry logic to run_git()
152: d703e7b = 148: a4164b8 Adjust README.md for microsoft/git
136: b6e2b8a = 149: 5ecf3bb test-gvfs-protocol: add cache_http_503 to mayhem
137: 5726a9e = 150: 9791d9d release: include GIT_BUILT_FROM_COMMIT in MacOS build
153: 5a6d8aa = 151: e4a5905 scalar: support the
configcommand for backwards compatibility138: 7dbb617 = 152: 6dbf7cf t5799: add unit tests for new
gvfs.fallbackconfig setting139: 374658f = 153: 4260d8a release: remove the obsolete GitHub installer workflow
154: 9d123db = 154: 637a8d7 scalar: implement a minimal JSON parser
155: 041eda1 = 155: 5a7e556 scalar clone: support GVFS-enabled remote repositories
156: 0845a2a = 156: e831f8d test-gvfs-protocol: also serve smart protocol
157: ba78067 = 157: f71f87e gvfs-helper: add the
endpointcommand158: 4c3a323 = 158: 7ac7981 dir_inside_of(): handle directory separators correctly
159: d8cea53 = 159: 4a3752c scalar: disable authentication in unattended mode
160: fdc5074 = 160: 6123963 abspath: make strip_last_path_component() global
161: 91d162e = 161: 83e9639 scalar: do initialize
gvfs.sharedCache162: ac8efd7 = 162: fdcad07 scalar diagnose: include shared cache info
163: 98d8206 = 163: 01b3708 scalar: only try GVFS protocol on https:// URLs
164: 745ea26 = 164: 25b769d scalar: verify that we can use a GVFS-enabled repository
165: b8bfc94 = 165: d79d71c scalar: add the
cache-servercommand166: ded06e2 = 166: f50912e scalar: add a test toggle to skip accessing the vsts/info endpoint
167: 6e6102b = 167: d7941ff scalar: adjust documentation to the microsoft/git fork
168: f622b16 = 168: bfd6b9f scalar: enable untracked cache unconditionally
175: 3ad5e6b = 169: cbb2ebb scalar: parse
clone --no-fetch-commits-and-treesfor backwards compatibility177: 3f5f933 = 170: 7e1217e scalar: make GVFS Protocol a forced choice
179: 185c9b9 = 171: 538a7a8 scalar: work around GVFS Protocol HTTP/2 failures
181: bd1c66e = 172: 862ef02 gvfs-helper-client: clean up server process(es)
169: 437dd9e = 173: be59a89 add/rm: allow adding sparse entries when virtual
183: 3525abe = 174: 8e728f4 scalar diagnose: accommodate Scalar's Functional Tests
170: c1cd1e9 = 175: fd0b38a sparse-checkout: add config to disable deleting dirs
185: 173fbe8 = 176: 04c574e ci: run Scalar's Functional Tests
171: b8c4907 = 177: 21beda0 diff: ignore sparse paths in diffstat
187: 78131bd = 178: 5a76643 scalar: upgrade to newest FSMonitor config setting
172: 6399fd4 = 179: 1f236df repo-settings: enable sparse index by default
173: 5c5749e = 180: 7960031 TO-UPSTREAM: sequencer: avoid progress when stderr is redirected
174: ff97e0d = 181: 909041c TO-CHECK: t1092: use quiet mode for rebase tests
176: 2c2f23b = 182: 41d9d91 reset: fix mixed reset when using virtual filesystem
178: 57d01e4 = 183: 6c84673 diff(sparse-index): verify with partially-sparse
180: 9452c72 = 184: 3195c9e stash: expand testing for
git stash -u182: d702dee = 185: cf1c47d sparse-index: add ensure_full_index_with_reason()
184: 63a372c = 186: ff6b08e treewide: add reasons for expanding index
186: 1a82f14 = 187: 0b9952a treewide: custom reasons for expanding index
188: 5344e5f = 188: 2232ab1 sparse-index: add macro for unaudited expansions
189: 9a468b7 = 189: a3803a7 Docs: update sparse index plan with logging
190: ebccc52 = 190: 016b76e sparse-index: log failure to clear skip-worktree
191: 3ae6c7a = 191: 87f33f9 stash: use -f in checkout-index child process
192: b99e79c = 192: 6f7b471 sparse-index: do not copy hashtables during expansion
193: 39962f1 = 193: eff3c45 TO-UPSTREAM: sub-process: avoid leaking
cmd194: f43dc34 = 194: 9b04f1a remote-curl: release filter options before re-setting them
195: 99f1c46 = 195: b2707e1 transport: release object filter options
196: 7717442 = 196: a5a64ee push: don't reuse deltas with path walk
197: 54df6d5 = 197: 381f03f maintenance: add cache-local-objects maintenance task
198: e928dde = 198: c9b802b scalar.c: add cache-local-objects task
199: 7eb9335 = 199: 7d98df5 hooks: add custom post-command hook config
204: ce86290 = 200: eadfb3d revision: defensive programming
207: 6e52191 = 201: 1d11c5d get_parent(): defensive programming
210: 5425810 = 202: de0db57 fetch-pack: defensive programming
212: 7dca882 = 203: ecef271 unparse_commit(): defensive programming
214: f090180 = 204: 8182273 verify_commit_graph(): defensive programming
216: 892800a = 205: e9a0fa5 stash: defensive programming
211: 5477bb3 = 206: ce409d6 codeql: run static analysis as part of CI builds
200: 350ead2 = 207: 4584b36 cat_one_file(): make it easy to see that the
sizevariable is initialized218: c1f3602 = 208: e8dfe54 stash: defensive programming
201: 13df2a1 = 209: 8b429e7 TO-UPSTREAM: Docs: fix asciidoc failures from short delimiters
213: c62e391 = 210: 10f28ea codeql: publish the sarif file as build artifact
202: 6356600 = 211: b83b568 fsck: avoid using an uninitialized variable
220: bc1b052 = 212: bd57977 push: defensive programming
222: 721be97 = 213: aa4c7bc test-tool repository: check return value of
lookup_commit()203: 0ca1364 = 214: 4c96fdd hooks: make hook logic memory-leak free
215: 1496405 = 215: cc2fb95 codeql: disable a couple of non-critical queries for now
205: e05a1ac = 216: c023a8c load_revindex_from_disk(): avoid accessing uninitialized data
223: 370ed28 = 217: fe28fdb fetch: defensive programming
225: 1ceab82 = 218: 6c0fec2 shallow: handle missing shallow commits gracefully
206: 3519feb = 219: 0f6ccae t0401: test post-command for alias, version, typo
217: 33f0a8f = 220: 4b9108d date: help CodeQL understand that there are no leap-year issues here
208: 05ca572 = 221: 24347f7 load_pack_mtimes_file(): avoid accessing uninitialized data
226: 51b2566 = 222: 0ab6b13 inherit_tracking(): defensive programming
228: f1c91aa = 223: f910864 commit-graph: suppress warning about using a stale stack addresses
209: e6ec9ec = 224: c73f70e hooks: better handle config without gitdir
219: fe93246 = 225: b807b8b help: help CodeQL understand that consuming envvars is okay here
221: 8587b48 = 226: 2d80402 ctype: help CodeQL understand that
sane_istest()does not access array past end224: 2aa788c = 227: 889b5bc ctype: accommodate for CodeQL misinterpreting the
zinmallocz()227: 8ba05a9 = 228: 9bd4d71 strbuf_read: help with CodeQL misunderstanding that
strbuf_read()does NUL-terminate correctly229: 60150d8 = 229: 65e9edc codeql: also check JavaScript code
230: 4536990 = 230: 586f61a scalar: add run_git_argv
231: a7dad14 = 231: 3872753 scalar: add --ref-format option to scalar clone
232: ab3a54d = 232: 86a5d01 gvfs-helper: skip collision check for loose objects
233: 17475dd = 233: 8f2d027 gvfs-helper: emit advice on transient errors
234: 9e70516 = 234: 41b6372 gvfs-helper: avoid collision check for packfiles
235: c20f6d5 = 235: 2ab4358 t5799: update cache-server methods for multiple instances
236: 6273fc9 = 236: 60cd821 gvfs-helper: override cache server for prefetch
237: 7327807 = 237: 96b644d gvfs-helper: override cache server for get
238: 1338aca = 238: 48a86cb gvfs-helper: override cache server for post
239: 83eb1e6 = 239: 730a739 t5799: add test for all verb-specific cache-servers together
240: 6f0f923 = 240: b573a64 lib-gvfs-helper: create helper script for protocol tests
241: ffcd3cf = 241: b4b2e41 t579*: split t5799 into several parts
242: 51d9c4c = 242: 65a1b01 scalar: add ---cache-server-url options
243: ad6b63a = 243: b9c5de0 Restore previous errno after post command hook
244: a3a424b = 244: 328b363 t9210: differentiate origin and cache servers
245: 457a1e1 = 245: 8b82747 unpack-trees: skip lstats for deleted VFS entries in checkout
246: fc1199e = 246: 7f1e0fc worktree: conditionally allow worktree on VFS-enabled repos
247: 7aaf1bd = 247: e8189bc gvfs-helper: send X-Session-Id headers
248: 96c217c = 248: 8368c93 gvfs-helper: create shared object cache if missing
249: 7467920 = 249: 61c0d3f gvfs: add gvfs.sessionKey config
250: a48ce17 = 250: c43dbab gvfs: clear DIE_IF_CORRUPT in streaming incore fallback
251: 4b047ac = 251: 786638a worktree remove: use GVFS_SUPPORTS_WORKTREES for skip-clean-check gate
252: 588e91e = 252: 7144c57 ci: add new VFS for Git functional tests workflow
253: 3ef7d12 = 253: 351b889 azure-pipelines: add stub release pipeline for Azure
254: 5289332 = 254: 9334b6d diff: add renameThreshold configuration option
256: 80edcbc = 255: 7cfead7 gvfs-helper: separate packfile extraction from indexing
255: 75ea3dd = 256: 1b9fed5 blame: add blame.renames, blame.renameThreshold, blame.renameLimit
257: 5d5dcb4 = 257: 9d90d6f gvfs-helper: run prefetch index-pack in parallel
258: 184a4d6 = 258: 333e8df gvfs-helper: add gvfs.prefetchThreads config for parallel prefetch
259: f1da780 = 259: 20e9452 azure-pipelines: add ESRP code signing
260: 60d911e = 260: 5160950 azure-pipelines: allow overriding Git version
261: c54863b = 261: c95d2e5 azure-pipelines: build, sign and stage the Linux Debian package
262: 6c849d0 = 262: 807d852 azure-pipelines: add signed macOS ARM64 releases
263: 376fb65 = 263: 6f802d1 azure-pipelines: build, sign and stage the Windows installer
264: c6795be = 264: cd44034 azure-pipelines: enable on tag push, default ESRP and GitHub release on
265: e7f6d3b = 265: 9aec7c7 release: binskim for Windows
266: 6dce414 = 266: 1453163 release: suppress unfixable binskim findings
267: 9a69fe5 = 267: b88a912 binskim: add baseline
268: 9a110d6 = 268: e1e2078 checkout: preserve skip-worktree for virtual filesystem paths
269: 3109aff = 269: 463af91 ci(vfs): install the GCC-compatible Rust target before building
270: b602ad3 = 270: 32a70e4 release-homebrew: add a hand-run script to replace the workflow
271: 40b58bb = 271: f16752c release-vfsforgit: add hand-run script to supersede the workflow
272: f097bbe = 272: ac2bd7e .github: add release-winget.sh to open winget-pkgs PR
273: 1902c40 = 273: 6c8b20f trace2: tolerate failed timestamp formatting
274: 3760c89 = 274: 8ec064c reset --mixed: clear skip-worktree for all changed entries in VFS mode
275: 8c65397 = 275: 294138c send-pack: add gvfs.negativeRefCheck to skip missing negatives
276: 1578839 = 276: 78c3276 odb: scan all sources' packfiles before loose objects
277: f2235f4 = 277: f5ca4ad scalar: add --[no-]prefetch option
278: f4cc03f = 278: 49856fe scalar: request for commit via POST
279: 87f7201 = 279: b366cf7 odb: warn when ignoring unusable alternates
280: 78da126 = 280: 6d5c156 ci: avoid vcpkg telemetry contention during MSBuild
281: 2156aaa = 281: 497e82d rust: honor the active MinGW prefix when invoking Cargo
282: 07147aa = 282: af775f2 cmake: default the Windows runtime prefix to UCRT64
283: aec46ac = 283: 4356260 gvfs-helper: add gvfs.postThreads config option
284: b6bbc22 = 284: b9221b9 http: factor reusable curl handle preparation
285: b978a96 = 285: 8259bdb gvfs-helper: parallelize POST object requests
286: 0e1942f = 286: d0c509c gvfs-helper: preserve POST failure handling in parallel mode
287: 84b71a5 = 287: 10ae4bb t5798: test parallel POST object requests
288: fa0381c = 288: 1348610 t5798: test parallel POST failure handling