Skip to content

Rebase to Git for Windows 2.56.0 - #995

Merged
Johannes Schindelin (dscho) merged 364 commits into
vfs-2.56.0from
tentative/vfs-2.56.0
Sep 29, 2026
Merged

Johannes Schindelin (dscho) merged 364 commits into
vfs-2.56.0from
tentative/vfs-2.56.0

Conversation

@dscho

Copy link
Copy Markdown
Member
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.exe to 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 structure

  • 20: 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

    @@ Commit message
      ## GIT-VERSION-GEN ##
     @@
      
    - DEF_VER=v2.56.0-rc2
    + DEF_VER=v2.56.0
      
     +# Identify microsoft/git via a distinct version suffix
     +DEF_VER=$DEF_VER.vfs.0.0
  • 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-components workflow in msft-git

  • 120: 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 universal

  • 140: 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 config command for backwards compatibility

  • 138: 7dbb617 = 152: 6dbf7cf t5799: add unit tests for new gvfs.fallback config setting

  • 139: 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 endpoint command

  • 158: 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.sharedCache

  • 162: 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-server command

  • 166: 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-trees for backwards compatibility

  • 177: 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 -u

  • 182: 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 cmd

  • 194: 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 size variable is initialized

  • 218: 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 end

  • 224: 2aa788c = 227: 889b5bc ctype: accommodate for CodeQL misinterpreting the z in mallocz()

  • 227: 8ba05a9 = 228: 9bd4d71 strbuf_read: help with CodeQL misunderstanding that strbuf_read() does NUL-terminate correctly

  • 229: 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

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice clean range-diff! ❤️

@dscho
Johannes Schindelin (dscho) merged commit 0faae01 into vfs-2.56.0 Sep 29, 2026
391 of 394 checks passed
@dscho
Johannes Schindelin (dscho) deleted the tentative/vfs-2.56.0 branch September 29, 2026 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants