Skip to content

Rebase to Git for Windows 2.56.0-rc2 - #991

Merged
Johannes Schindelin (dscho) merged 364 commits into
vfs-2.56.0-rc2from
tentative/vfs-2.56.0-rc2
Sep 23, 2026
Merged

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

Conversation

@dscho

Copy link
Copy Markdown
Member
Range-diff relative to tentative/vfs-2.56.0-rc1
  • 1: e8b6f68 = 1: 9379aac t: remove advice from some tests

  • 2: a837ddc = 2: a3a6696 survey: calculate more stats on refs

  • 3: d2d8b2b = 3: 5a214a6 survey: show some commits/trees/blobs histograms

  • 4: 4a763a5 = 4: 3448f4c survey: add vector of largest objects for various scaling dimensions

  • 5: 48f7678 = 5: 7f5623f survey: add pathname of blob or tree to large_item_vec

  • 6: 84ee7a3 = 6: d792365 survey: add commit-oid to large_item detail

  • 7: bac7b8a = 7: 609d189 fixup! ci(dockerized): do show the result of failing tests again

  • 8: 679d30d = 8: 066a7b5 survey: add commit name-rev lookup to each large_item

  • 9: 7ce6a12 = 9: c92da0d fixup! Add a GitHub workflow to verify that Git/Scalar work in Nano Server

  • 10: a10d5f5 = 10: 6c32b4c survey: add --no-name-rev option

  • 11: 91ae0a0 = 11: 49c68aa fixup! mingw: allow git.exe to be used instead of the "Git wrapper"

  • 12: 2a72bc2 = 12: bc80ee7 sparse-index.c: fix use of index hashes in expand_index

  • 13: 8545e8f = 13: 9957c08 survey: started TODO list at bottom of source file

  • 14: c558d23 = 14: 501f636 fixup! Add an AGENTS.md file to help with AI-assisted debugging/development

  • 15: 62dfe30 = 15: 00af8d1 t5300: confirm failure of git index-pack when non-idx suffix requested

  • 16: 4b6a062 = 16: 8244a85 t1092: add test for untracked files and directories

  • 17: 5d6b31e = 17: 200308c survey: expanded TODO list at the bottom of the source file

  • 18: 3e3cda8 = 18: 2220bdb fixup! survey: turn into a thin shim over git repo structure

  • 19: 21a20d7 = 19: b57764e index-pack: disable rev-index if index file has non .idx suffix

  • 20: 6e71e20 = 20: dcc6873 survey: expanded TODO with more notes

  • 21: b6e9a10 = 21: db73bb5 trace2: prefetch value of GIT_TRACE2_DST_DEBUG at startup

  • 22: 4b3f05f = 22: 1228c43 reset --stdin: trim carriage return from the paths

  • 23: 2315267 ! 23: 6d86dbe Identify microsoft/git via a distinct version suffix

    @@ Commit message
      ## GIT-VERSION-GEN ##
     @@
      
    - DEF_VER=v2.56.0-rc1
    + DEF_VER=v2.56.0-rc2
      
     +# Identify microsoft/git via a distinct version suffix
     +DEF_VER=$DEF_VER.vfs.0.0
  • 24: 387d42e = 24: fd7d55c gvfs: ensure that the version is based on a GVFS tag

  • 25: 8fe0318 = 25: e7e05a6 gvfs: add a GVFS-specific header file

  • 26: 6bb6cea = 26: 2591c20 gvfs: add the core.gvfs config setting

  • 27: 3104500 = 27: ad0ec9f gvfs: add the feature to skip writing the index' SHA-1

  • 63: bc828ac = 28: 70a66f3 gvfs: add the feature that blobs may be missing

  • 64: efe7aac = 29: d694564 gvfs: prevent files to be deleted outside the sparse checkout

  • 65: 7cd8abe = 30: 82c6d2b gvfs: optionally skip reachability checks/upload pack during fetch

  • 66: 9e059c1 = 31: 480ec32 gvfs: ensure all filters and EOL conversions are blocked

  • 67: 936c3cb = 32: fd6c2f9 gvfs: allow "virtualizing" objects

  • 68: 7078bf0 = 33: 1a0b292 Hydrate missing loose objects in check_and_freshen()

  • 69: 52d65c3 = 34: 0bec9c1 sha1_file: when writing objects, skip the read_object_hook

  • 70: 0db9709 = 35: 4a963ac gvfs: add global command pre and post hook procs

  • 71: cca50d8 = 36: e88ea77 t0400: verify that the hook is called correctly from a subdirectory

  • 72: dab4515 = 37: a915109 t0400: verify core.hooksPath is respected by pre-command

  • 73: 379801e = 38: 95c2ea4 Pass PID of git process to hooks.

  • 74: f27b308 = 39: 0776575 sparse-checkout: make sure to update files with a modify/delete conflict

  • 75: 5f08216 = 40: 1189373 worktree: allow in Scalar repositories

  • 76: e638b16 = 41: fb37987 sparse-checkout: avoid writing entries with the skip-worktree bit

  • 77: 919aede = 42: 1d473ff Do not remove files outside the sparse-checkout

  • 78: d4d2f19 = 43: d41acf8 send-pack: do not check for sha1 file when GVFS_MISSING_OK set

  • 79: 14afb0c = 44: 7ec8755 gvfs: allow corrupt objects to be re-downloaded

  • 80: df9d855 = 45: 6ca4180 cache-tree: remove use of strbuf_addf in update_one

  • 81: d744a50 = 46: 78e28a9 gvfs: block unsupported commands when running in a GVFS repo

  • 82: 5293057 = 47: 50dc39c gvfs: allow overriding core.gvfs

  • 83: fe70f93 = 48: d9f471a BRANCHES.md: Add explanation of branches and using forks

  • 84: e3dce25 = 49: c0336a6 Add virtual file system settings and hook proc

  • 85: 155b7d1 = 50: 988bd50 virtualfilesystem: don't run the virtual file system hook if the index has been redirected

  • 86: 71d3838 = 51: b9dc8e0 virtualfilesystem: check if directory is included

  • 87: 3b7e478 = 52: 51ffe7c backwards-compatibility: support the post-indexchanged hook

  • 88: 6aa05b5 = 53: 0c658dd gvfs: verify that the built-in FSMonitor is disabled

  • 89: 32f6ed5 = 54: 99c1c0a wt-status: add trace2 data for sparse-checkout percentage

  • 90: 9bfac18 = 55: 5e43e31 status: add status serialization mechanism

  • 91: 193e7a2 = 56: 44c08a2 Teach ahead-behind and serialized status to play nicely together

  • 92: 3ab1d75 = 57: a6fd408 status: serialize to path

  • 93: 9be55c9 = 58: d0eafba status: reject deserialize in V2 and conflicts

  • 94: 0b0ec59 = 59: c497222 serialize-status: serialize global and repo-local exclude file metadata

  • 95: af8635a = 60: 20c3ac1 status: deserialization wait

  • 96: 787969c = 61: 27ab58a status: deserialize with -uno does not print correct hint

  • 97: f29d65e = 62: c93606e fsmonitor: check CE_FSMONITOR_VALID in ce_uptodate

  • 98: a916773 = 63: 0479cb5 fsmonitor: add script for debugging and update script for tests

  • 99: b9e929c = 64: b60e2e0 status: disable deserialize when verbose output requested.

  • 100: 7503d99 = 65: d436dce t7524: add test for verbose status deserialzation

  • 101: 5aa1c05 = 66: f009728 deserialize-status: silently fallback if we cannot read cache file

  • 102: 115a64e = 67: b14125e gvfs:trace2:data: add trace2 tracing around read_object_process

  • 103: ec1b027 = 68: ac8472b gvfs:trace2:data: status deserialization information

  • 104: 6c3dfbd = 69: 92603b7 gvfs:trace2:data: status serialization

  • 105: b5d3600 = 70: 1081120 gvfs:trace2:data: add vfs stats

  • 106: 9ae932b = 71: c329d80 trace2: refactor setting process starting time

  • 107: 3f1d7c1 = 72: 310b456 trace2:gvfs:experiment: report_tracking

  • 109: f0e4207 = 73: f4de229 trace2:gvfs:experiment: read_cache: annotate thread usage in read-cache

  • 111: dc929de = 74: e9274f4 trace2:gvfs:experiment: read-cache: time read/write of cache-tree extension

  • 113: b407c07 = 75: 865c2fe trace2:gvfs:experiment: add region to apply_virtualfilesystem()

  • 115: 6dfe362 = 76: d8b8e55 trace2:gvfs:experiment: add region around unpack_trees()

  • 108: 8718e26 = 77: f342d73 git.c: add VFS enabled cmd blocking

  • 117: 7554357 = 78: 98f6824 trace2:gvfs:experiment: add region to cache_tree_fully_valid()

  • 110: be11956 = 79: 1f6b9c9 git.c: permit repack cmd in Scalar repos

  • 119: 26176b8 = 80: 0556c3c trace2:gvfs:experiment: add unpack_entry() counter to unpack_trees() and report_tracking()

  • 112: 491ddfa = 81: 3de6f10 git.c: permit fsck cmd in Scalar repos

  • 120: f09b67d = 82: ee78215 trace2:gvfs:experiment: increase default event depth for unpack-tree data

  • 114: 76b2053 = 83: b10c2ef git.c: permit prune cmd in Scalar repos

  • 121: 65f6c35 = 84: 43baf0f trace2:gvfs:experiment: add data for check_updates() in unpack_trees()

  • 116: af6ff28 = 85: e539d2c worktree: remove special case GVFS cmd blocking

  • 122: 11ffcc8 = 86: 09ea369 Trace2:gvfs:experiment: capture more 'tracking' details

  • 118: b51cffb = 87: 137c835 builtin/repack.c: emit warning when shared cache is present

  • 123: 3fa557b = 88: e634502 credential: set trace2_child_class for credential manager children

  • 124: bc332b6 = 89: 9940d89 sub-process: do not borrow cmd pointer from caller

  • 125: 09086b7 = 90: c2fc078 sub-process: add subprocess_start_argv()

  • 126: fa9f21e = 91: 68f3fe4 sha1-file: add function to update existing loose object cache

  • 127: 502918c = 92: 49754d2 index-pack: avoid immediate object fetch while parsing packfile

  • 128: fcb6c54 = 93: 1985059 gvfs-helper: create tool to fetch objects using the GVFS Protocol

  • 129: 2db620a ! 94: f00f5f0 (which auto-squashed c5d6bc6) sha1-file: create shared-cache directory if it doesn't exist

    @@ gvfs-helper.c
      //
      //                 git> get
      //                 git> <oid>
    +@@
    + #include "abspath.h"
    + #include "progress.h"
    + #include "trace2.h"
    ++#include "gvfs.h"
    + 
    + static const char * const main_usage[] = {
    + 	N_("git gvfs-helper [<main_options>] config      [<options>]"),
     @@ gvfs-helper.c: static int option_parse_cache_server_mode(const struct option *opt,
      }
      
    @@ gvfs-helper.c: static int option_parse_cache_server_mode(const struct option *op
     +		strbuf_addbuf(&gvfs_shared_cache_pathname, &buf_arg);
      
     -	gvfs_shared_cache_pathname = arg;
    -+		odb_add_to_alternates_memory(the_repository->objects, buf_arg.buf);
    ++		add_gvfs_shared_cache_to_alternates(the_repository->objects, buf_arg.buf);
      
     -	return 0;
     +		strbuf_release(&buf_arg);
    @@ gvfs-helper.c: static int option_parse_cache_server_mode(const struct option *op
     +		strbuf_setlen(&gvfs_shared_cache_pathname, 0);
     +		strbuf_addbuf(&gvfs_shared_cache_pathname, &buf_arg);
     +
    -+		odb_add_to_alternates_memory(the_repository->objects, buf_arg.buf);
    ++		add_gvfs_shared_cache_to_alternates(the_repository->objects, buf_arg.buf);
     +
     +		/*
     +		 * alt_odb_usable() releases gvfs_shared_cache_pathname
    @@ gvfs-helper.c: static void approve_cache_server_creds(void)
      
      /*
     
    + ## gvfs.h ##
    +@@ gvfs.h: struct repository;
    + int gvfs_config_is_set(struct repository *r, int mask);
    + int gvfs_virtualize_objects(struct repository *r);
    + 
    ++struct object_database;
    ++struct odb_source *add_gvfs_shared_cache_to_alternates(struct object_database *odb,
    ++						       const char *dir);
    ++
    + #endif /* GVFS_H */
    +
      ## odb.c ##
     @@ odb.c: int odb_mkstemp(struct object_database *odb,
      	return xmkstemp_mode(temp_filename->buf, mode);
    @@ odb.c: int odb_mkstemp(struct object_database *odb,
      	/* Detect cases where alternate disappeared */
      	if (!is_directory(path)) {
      		error(_("object directory %s does not exist; "
    +@@ odb.c: static struct odb_source *odb_add_alternate_recursively(struct object_database *
    + 	return alternate;
    + }
    + 
    ++struct odb_source *add_gvfs_shared_cache_to_alternates(struct object_database *odb,
    ++						       const char *dir)
    ++{
    ++	return odb_add_alternate_recursively(odb, dir, 0);
    ++}
    ++
    + void odb_add_to_alternates_file(struct object_database *odb,
    + 				const char *dir)
    + {
     @@ odb.c: int odb_for_each_alternate(struct object_database *odb,
      static void odb_prepare_alternates(struct object_database *odb,
      				   const char *alternate_db)
  • 131: 51f1386 = 95: f78cabb gvfs-helper: better handling of network errors

  • 132: 7f4a505 = 96: 376220a gvfs-helper-client: properly update loose cache with fetched OID

  • 133: aea7e33 = 97: e4f7f48 gvfs-helper: V2 robust retry and throttling

  • 134: 6780db4 = 98: c612bae gvfs-helper: expose gvfs/objects GET and POST semantics

  • 135: ca5a532 = 99: 3d4fe11 gvfs-helper: dramatically reduce progress noise

  • 136: 669cda6 = 100: cf008d8 gvfs-helper: handle pack-file after single POST request

  • 137: 57d89ba = 101: a1297ba test-gvfs-prococol, t5799: tests for gvfs-helper

  • 138: d0bbcdd = 102: 5c7f6d0 gvfs-helper: move result-list construction into install functions

  • 139: b6b3d0f = 103: 06ae72f t5799: add support for POST to return either a loose object or packfile

  • 140: 085879c = 104: 773b79d t5799: cleanup wc-l and grep-c lines

  • 141: 1761118 = 105: a80c966 gvfs-helper: verify loose objects after write

  • 142: 9e4d6d2 = 106: 1b84a7c t7599: create corrupt blob test

  • 143: a366684 = 107: 5103ca3 gvfs-helper: add prefetch support

  • 144: 9081419 = 108: 398a98a gvfs-helper: add prefetch .keep file for last packfile

  • 145: 3525dc8 = 109: ed445c7 gvfs-helper: do one read in my_copy_fd_len_tail()

  • 146: c49e061 = 110: 5a2160d gvfs-helper: move content-type warning for prefetch packs

  • 147: da218cf = 111: c4512c7 fetch: use gvfs-helper prefetch under config

  • 148: 5a0c9ce = 112: da74952 gvfs-helper: better support for concurrent packfile fetches

  • 149: d35d1ad = 113: 65bcb62 remote-curl: do not call fetch-pack when using gvfs-helper

  • 150: 8a3a478 = 114: 4ac394c fetch: reprepare packs before checking connectivity

  • 151: e6abb7b = 115: 3124a19 gvfs-helper: retry when creating temp files

  • 152: 9074f57 = 116: 23bc195 sparse: avoid warnings about known cURL issues in gvfs-helper.c

  • 159: 15955cf = 117: e487418 maintenance: care about gvfs.sharedCache config

  • 161: cb7ad0b = 118: 8299e93 unpack-trees:virtualfilesystem: Improve efficiency of clear_ce_flags

  • 167: e083895 = 119: dbc1f92 Disable the monitor-components workflow in msft-git

  • 169: 0c2b041 = 120: 2e6f7ca .github: enable windows builds on microsoft fork

  • 170: a6fc155 = 121: a1dc4ee .github/actions/akv-secret: add action to get secrets

  • 171: 1cb5171 = 122: 94c21fa release: create initial Windows installer build workflow

  • 173: 3b76db4 = 123: 770c9f2 help: special-case HOST_CPU universal

  • 175: 0f618ed = 124: e0fe67c release: add Mac OSX installer build

  • 177: d52f6fb = 125: 0256aea release: build unsigned Ubuntu .deb package

  • 153: ae1b721 = 126: de0c8d2 gvfs-helper: add --max-retries to prefetch verb

  • 179: 3abdd32 = 127: d5e0466 release: add signing step for .deb package

  • 154: 550d785 = 128: 6027dd2 t5799: add tests to detect corrupt pack/idx files in prefetch

  • 181: a4ca71e = 129: 139b0fe release: create draft GitHub release with packages & installers

  • 155: 824accb = 130: 36d7a30 gvfs-helper: ignore .idx files in prefetch multi-part responses

  • 183: dd44bd0 = 131: 4d09afc build-git-installers: publish gpg public key

  • 156: 1c06ba8 = 132: 7554a9a t5799: explicitly test gvfs-helper --fallback and --no-fallback

  • 185: ad19277 = 133: ccfe9a8 release: continue pestering until user upgrades

  • 157: 8f1f114 = 134: f0582ab gvfs-helper: don't fallback with new config

  • 187: 6721b29 = 135: 73901ea dist: archive HEAD instead of HEAD^{tree}

  • 158: cf79810 = 136: b6e2b8a test-gvfs-protocol: add cache_http_503 to mayhem

  • 189: b280761 = 137: 5726a9e release: include GIT_BUILT_FROM_COMMIT in MacOS build

  • 160: b5cab59 = 138: 7dbb617 t5799: add unit tests for new gvfs.fallback config setting

  • 191: fa4f8aa = 139: 374658f release: remove the obsolete GitHub installer workflow

  • 28: dad67c0 = 140: 9bf7ec5 scalar: set the config write-lock timeout to 150ms

  • 29: 0e97b91 = 141: 4cece70 scalar: set the config write-lock timeout to 150ms

  • 30: 6e5b9ce = 142: ccd1822 scalar: upgrade the config lock timeout setting automagically

  • 162: db7bf8e = 143: bc5ee0e update-microsoft-git: create barebones builtin

  • 31: e3d9c2c = 144: 45e6e6e config: (handle and) warn about deprecated lock timeout setting

  • 163: 3d22821 = 145: 304b867 update-microsoft-git: Windows implementation

  • 32: c6dcc7d = 146: 45a0b08 scalar: add docs from microsoft/scalar

  • 164: 236dd62 = 147: a5f0546 update-microsoft-git: use brew on macOS

  • 165: 87eff26 = 148: 195c94f .github: reinstate ISSUE_TEMPLATE.md for microsoft/git

  • 33: 48f662a = 149: 40b79c9 scalar (Windows): use forward slashes as directory separators

  • 166: 0ca8687 = 150: 6199e21 .github: update PULL_REQUEST_TEMPLATE.md

  • 34: c836201 = 151: a22b2ac scalar: add retry logic to run_git()

  • 168: 3d8b726 = 152: d703e7b Adjust README.md for microsoft/git

  • 35: 8eeb0de = 153: 5a6d8aa scalar: support the config command for backwards compatibility

  • 172: 9959362 = 154: 9d123db scalar: implement a minimal JSON parser

  • 174: 2afa625 = 155: 041eda1 scalar clone: support GVFS-enabled remote repositories

  • 176: bc5eb4b = 156: 0845a2a test-gvfs-protocol: also serve smart protocol

  • 178: 284e0a0 = 157: ba78067 gvfs-helper: add the endpoint command

  • 180: 1f84a71 = 158: 4c3a323 dir_inside_of(): handle directory separators correctly

  • 182: e629027 = 159: d8cea53 scalar: disable authentication in unattended mode

  • 184: 6a60f66 = 160: fdc5074 abspath: make strip_last_path_component() global

  • 186: 59077f5 = 161: 91d162e scalar: do initialize gvfs.sharedCache

  • 188: 9531cdf = 162: ac8efd7 scalar diagnose: include shared cache info

  • 190: 04149c4 = 163: 98d8206 scalar: only try GVFS protocol on https:// URLs

  • 195: e4e0016 = 164: 745ea26 scalar: verify that we can use a GVFS-enabled repository

  • 197: 10ebb67 = 165: b8bfc94 scalar: add the cache-server command

  • 198: 161442e = 166: ded06e2 scalar: add a test toggle to skip accessing the vsts/info endpoint

  • 199: 70e8e5d = 167: 6e6102b scalar: adjust documentation to the microsoft/git fork

  • 201: df33d6d = 168: f622b16 scalar: enable untracked cache unconditionally

  • 192: ac5e537 = 169: 437dd9e add/rm: allow adding sparse entries when virtual

  • 193: 89e87c5 = 170: c1cd1e9 sparse-checkout: add config to disable deleting dirs

  • 194: ecac8e8 = 171: b8c4907 diff: ignore sparse paths in diffstat

  • 196: 3488094 = 172: 6399fd4 repo-settings: enable sparse index by default

  • 36: a9ee7c4 = 173: 5c5749e TO-UPSTREAM: sequencer: avoid progress when stderr is redirected

  • 200: bae5811 = 174: ff97e0d TO-CHECK: t1092: use quiet mode for rebase tests

  • 203: dbef07a = 175: 3ad5e6b scalar: parse clone --no-fetch-commits-and-trees for backwards compatibility

  • 202: 75d5414 = 176: 2c2f23b reset: fix mixed reset when using virtual filesystem

  • 205: e53877a = 177: 3f5f933 scalar: make GVFS Protocol a forced choice

  • 204: 4e56187 = 178: 57d01e4 diff(sparse-index): verify with partially-sparse

  • 207: fab48c9 = 179: 185c9b9 scalar: work around GVFS Protocol HTTP/2 failures

  • 206: 32e5af4 = 180: 9452c72 stash: expand testing for git stash -u

  • 209: f70640d = 181: bd1c66e gvfs-helper-client: clean up server process(es)

  • 208: f963cdc = 182: d702dee sparse-index: add ensure_full_index_with_reason()

  • 211: 42890de = 183: 3525abe scalar diagnose: accommodate Scalar's Functional Tests

  • 210: cedaeec = 184: 63a372c treewide: add reasons for expanding index

  • 213: 555d92e = 185: 173fbe8 ci: run Scalar's Functional Tests

  • 212: 4a598f6 = 186: 1a82f14 treewide: custom reasons for expanding index

  • 215: e79d611 = 187: 78131bd scalar: upgrade to newest FSMonitor config setting

  • 214: 7a1ee60 = 188: 5344e5f sparse-index: add macro for unaudited expansions

  • 216: f13ff22 = 189: 9a468b7 Docs: update sparse index plan with logging

  • 217: 118b6bb = 190: ebccc52 sparse-index: log failure to clear skip-worktree

  • 218: 713abdb = 191: 3ae6c7a stash: use -f in checkout-index child process

  • 219: ffa770d = 192: b99e79c sparse-index: do not copy hashtables during expansion

  • 220: b74aa97 = 193: 39962f1 TO-UPSTREAM: sub-process: avoid leaking cmd

  • 221: bf9f191 = 194: f43dc34 remote-curl: release filter options before re-setting them

  • 222: 84b8512 = 195: 99f1c46 transport: release object filter options

  • 223: 9acea34 = 196: 7717442 push: don't reuse deltas with path walk

  • 224: 5d6b49f = 197: 54df6d5 maintenance: add cache-local-objects maintenance task

  • 225: 6dab639 = 198: e928dde scalar.c: add cache-local-objects task

  • 226: 0cc3de9 = 199: 7eb9335 hooks: add custom post-command hook config

  • 37: 8413b20 = 200: 350ead2 cat_one_file(): make it easy to see that the size variable is initialized

  • 227: 54006fe = 201: 13df2a1 TO-UPSTREAM: Docs: fix asciidoc failures from short delimiters

  • 38: 2a33af0 = 202: 6356600 fsck: avoid using an uninitialized variable

  • 228: 699c357 = 203: 0ca1364 hooks: make hook logic memory-leak free

  • 41: 0dcf0ca = 204: ce86290 revision: defensive programming

  • 39: 043d525 = 205: e05a1ac load_revindex_from_disk(): avoid accessing uninitialized data

  • 229: 7eba3af = 206: 3519feb t0401: test post-command for alias, version, typo

  • 42: 0d6ccdd = 207: 6e52191 get_parent(): defensive programming

  • 40: 975532c = 208: 05ca572 load_pack_mtimes_file(): avoid accessing uninitialized data

  • 230: 8558aa6 = 209: e6ec9ec hooks: better handle config without gitdir

  • 43: 80ee9af = 210: 5425810 fetch-pack: defensive programming

  • 44: 3991a05 = 211: 5477bb3 codeql: run static analysis as part of CI builds

  • 45: 2625274 = 212: 7dca882 unparse_commit(): defensive programming

  • 46: bebfeea = 213: c62e391 codeql: publish the sarif file as build artifact

  • 47: 8c0cfd6 = 214: f090180 verify_commit_graph(): defensive programming

  • 48: 68098e0 = 215: 1496405 codeql: disable a couple of non-critical queries for now

  • 49: 1002a1e = 216: 892800a stash: defensive programming

  • 50: a728598 = 217: 33f0a8f date: help CodeQL understand that there are no leap-year issues here

  • 51: 8d99b7e = 218: c1f3602 stash: defensive programming

  • 52: 2c56230 = 219: fe93246 help: help CodeQL understand that consuming envvars is okay here

  • 53: a591bf1 = 220: bc1b052 push: defensive programming

  • 54: f539aa9 = 221: 8587b48 ctype: help CodeQL understand that sane_istest() does not access array past end

  • 55: 63c78c3 = 222: 721be97 test-tool repository: check return value of lookup_commit()

  • 56: d4d2bbb = 223: 370ed28 fetch: defensive programming

  • 57: 4647696 = 224: 2aa788c ctype: accommodate for CodeQL misinterpreting the z in mallocz()

  • 58: 8119da8 = 225: 1ceab82 shallow: handle missing shallow commits gracefully

  • 59: b8d6506 = 226: 51b2566 inherit_tracking(): defensive programming

  • 60: c5c7510 = 227: 8ba05a9 strbuf_read: help with CodeQL misunderstanding that strbuf_read() does NUL-terminate correctly

  • 61: 7f82c2a = 228: f1c91aa commit-graph: suppress warning about using a stale stack addresses

  • 62: 264244e = 229: 60150d8 codeql: also check JavaScript code

  • 130: c5d6bc6 < -: ----------- fixup! sha1-file: create shared-cache directory if it doesn't exist

  • 231: c77fe05 = 230: 4536990 scalar: add run_git_argv

  • 232: 7d67fa7 = 231: a7dad14 scalar: add --ref-format option to scalar clone

  • 233: 677b777 = 232: ab3a54d gvfs-helper: skip collision check for loose objects

  • 234: 9a5a7d8 = 233: 17475dd gvfs-helper: emit advice on transient errors

  • 235: 6edf57e = 234: 9e70516 gvfs-helper: avoid collision check for packfiles

  • 236: 25778e2 = 235: c20f6d5 t5799: update cache-server methods for multiple instances

  • 237: c8341af = 236: 6273fc9 gvfs-helper: override cache server for prefetch

  • 238: d8b669f = 237: 7327807 gvfs-helper: override cache server for get

  • 239: 2296011 = 238: 1338aca gvfs-helper: override cache server for post

  • 240: 3a717d1 = 239: 83eb1e6 t5799: add test for all verb-specific cache-servers together

  • 241: 22f9441 = 240: 6f0f923 lib-gvfs-helper: create helper script for protocol tests

  • 242: 8e807f3 = 241: ffcd3cf t579*: split t5799 into several parts

  • 243: 8f24271 = 242: 51d9c4c scalar: add ---cache-server-url options

  • 244: d8ae2cf = 243: ad6b63a Restore previous errno after post command hook

  • 245: 876afc3 = 244: a3a424b t9210: differentiate origin and cache servers

  • 246: e17bbfd = 245: 457a1e1 unpack-trees: skip lstats for deleted VFS entries in checkout

  • 247: 8073299 = 246: fc1199e worktree: conditionally allow worktree on VFS-enabled repos

  • 249: 1f725d7 = 247: 7aaf1bd gvfs-helper: send X-Session-Id headers

  • 248: fce704b = 248: 96c217c gvfs-helper: create shared object cache if missing

  • 250: 204ccf2 = 249: 7467920 gvfs: add gvfs.sessionKey config

  • 251: a044a27 = 250: a48ce17 gvfs: clear DIE_IF_CORRUPT in streaming incore fallback

  • 252: 334fb47 = 251: 4b047ac worktree remove: use GVFS_SUPPORTS_WORKTREES for skip-clean-check gate

  • 253: ef7f7fd = 252: 588e91e ci: add new VFS for Git functional tests workflow

  • 254: 08cd50f = 253: 3ef7d12 azure-pipelines: add stub release pipeline for Azure

  • 255: 4793e5f = 254: 5289332 diff: add renameThreshold configuration option

  • 257: f2e175d = 255: 75ea3dd blame: add blame.renames, blame.renameThreshold, blame.renameLimit

  • 256: 50951a5 = 256: 80edcbc gvfs-helper: separate packfile extraction from indexing

  • 258: e20ff86 = 257: 5d5dcb4 gvfs-helper: run prefetch index-pack in parallel

  • 259: 244d595 = 258: 184a4d6 gvfs-helper: add gvfs.prefetchThreads config for parallel prefetch

  • 260: 1631c47 = 259: f1da780 azure-pipelines: add ESRP code signing

  • 261: eb515d7 = 260: 60d911e azure-pipelines: allow overriding Git version

  • 262: cff8a32 = 261: c54863b azure-pipelines: build, sign and stage the Linux Debian package

  • 263: bac85b6 = 262: 6c849d0 azure-pipelines: add signed macOS ARM64 releases

  • 264: de16895 = 263: 376fb65 azure-pipelines: build, sign and stage the Windows installer

  • 265: 3051db2 = 264: c6795be azure-pipelines: enable on tag push, default ESRP and GitHub release on

  • 266: 36f0c21 = 265: e7f6d3b release: binskim for Windows

  • 267: e26f975 = 266: 6dce414 release: suppress unfixable binskim findings

  • 268: 1ac3713 = 267: 9a69fe5 binskim: add baseline

  • 269: 7b3aa78 = 268: 9a110d6 checkout: preserve skip-worktree for virtual filesystem paths

  • 270: 428f04e = 269: 3109aff ci(vfs): install the GCC-compatible Rust target before building

  • 271: f0a9340 = 270: b602ad3 release-homebrew: add a hand-run script to replace the workflow

  • 272: 6f360f9 = 271: 40b58bb release-vfsforgit: add hand-run script to supersede the workflow

  • 273: 5a089ba = 272: f097bbe .github: add release-winget.sh to open winget-pkgs PR

  • 274: 9b99ba8 = 273: 1902c40 trace2: tolerate failed timestamp formatting

  • 275: 846d5de = 274: 3760c89 reset --mixed: clear skip-worktree for all changed entries in VFS mode

  • 276: 36faa37 = 275: 8c65397 send-pack: add gvfs.negativeRefCheck to skip missing negatives

  • 277: 74d7f80 = 276: 1578839 odb: scan all sources' packfiles before loose objects

  • 278: 6fd9369 = 277: f2235f4 scalar: add --[no-]prefetch option

  • 279: a8aab29 = 278: f4cc03f scalar: request for commit via POST

  • 280: 919a530 = 279: 87f7201 odb: warn when ignoring unusable alternates

  • 281: 7bf7e90 = 280: 78da126 ci: avoid vcpkg telemetry contention during MSBuild

  • 282: a3273f7 = 281: 2156aaa rust: honor the active MinGW prefix when invoking Cargo

  • 283: 92bfd44 = 282: 07147aa cmake: default the Windows runtime prefix to UCRT64

  • 284: 5ae7fad = 283: aec46ac gvfs-helper: add gvfs.postThreads config option

  • 285: 2b87ce6 = 284: b6bbc22 http: factor reusable curl handle preparation

  • 286: dc15f86 = 285: b978a96 gvfs-helper: parallelize POST object requests

  • 287: e86ce06 = 286: 0e1942f gvfs-helper: preserve POST failure handling in parallel mode

  • 288: bc00162 = 287: 84b71a5 t5798: test parallel POST object requests

  • 289: eefe24c = 288: fa0381c t5798: test parallel POST failure handling

Create t/helper/test-gvfs-protocol.c and t/t5799-gvfs-helper.sh
to test gvfs-helper.

Create t/helper/test-gvfs-protocol.c as a stand-alone web server that
speaks the GVFS Protocol [1] and serves loose objects and packfiles
to clients.  It is borrows heavily from the code in daemon.c.
It includes a "mayhem" mode to cause various network and HTTP errors
to test the retry/recovery ability of gvfs-helper.

Create t/t5799-gvfs-helper.sh to test gvfs-helper.

[1] https://github.com/microsoft/VFSForGit/blob/master/Protocol.md

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The gvfs-helper allows us to download prefetch packs using a simple
subprocess call. The gvfs-helper-client.h method will automatically
compute the timestamp if passing 0, and passing NULL for the number
of downloaded packs is valid.

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
- include `scalar`
- build signed .dmg & .pkg for target OS version 10.6
- upload artifacts to workflow

Co-authored-by: Lessley Dennington <ldennington@github.com>
gvfs-helper prints a "loose <oid>" or "packfile <name>" messages after
they are received to help invokers update their in-memory caches.
Move the code to accumulate these messages in the result_list into
the install_* functions rather than waiting until the end.

POST requests containing 1 object may return a loose object or a packfile
depending on whether the object is a commit or non-commit.  Delaying the
message generation just complicated the caller.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Teach gvfs-helper to better support the concurrent fetching of the
same packfile by multiple instances.

If 2 instances of gvfs-helper did a POST and requested the same set of
OIDs, they might receive the exact same packfile (same checksum SHA).
Both processes would then race to install their copy of the .pack and
.idx files into the ODB/pack directory.

This is not a problem on Unix (because of filesystem semantics).

On Windows, this can cause an EBUSY/EPERM problem for the loser while
the winner is holding a handle to the target files.  (The existing
packfile code already handled simple the existence and/or replacement
case.)

The solution presented here is to silently let the loser claim
victory IIF the .pack and .idx are already present in the ODB.
(We can't check this in advance because we don't know the packfile
SHA checksum until after we receive it and run index-pack.)

We avoid using a per-packfile lockfile (or a single lockfile for
the `vfs-` prefix) to avoid the usual issues with stale lockfiles.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
- include `scalar`
- build & upload unsigned .deb package

Co-authored-by: Lessley Dennington <ldennington@github.com>
Co-authored-by: Sverre Johansen <sverre.johansen@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Earlier versions of the test always returned a packfile in response to a POST.
Now we look at the number of objects in the POST request.

If > 1, always send a packfile.

If = 1 and it is a commit, send a packfile.
Otherwise, send a loose object.

This is to better model the behavior of the GVFS server/protocol which
treats commits differently.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
When using the GVFS protocol, we should _never_ call "git fetch-pack"
to attempt downloading a pack-file via the regular Git protocol. It
appears that the mechanism that prevented this in the VFS for Git
world is due to the read-object hook populating the commits at the
new ref tips in a different way than the gvfs-helper does.

By acting as if the fetch-pack succeeds here in remote-curl, we
prevent a failed fetch.

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Construct 2 new unit tests to explicitly verify the use of
`--fallback` and `--no-fallback` arguments to `gvfs-helper`.

When a cache-server is enabled, `gvfs-helper` will try to fetch
objects from it rather than the origin server.  If the cache-server
fails (and all cache-server retry attempts have been exhausted),
`gvfs-helper` can optionally "fallback" and try to fetch the objects
from the origin server.  (The retry logic is also applied to the
origin server, if the origin server fails on the first request.)

Add new unit tests to verify that `gvfs-helper` respects both the
`--max-retries` and `--[no-]fallback` arguments.

We use the "http_503" mayhem feature of the `test_gvfs_protocol`
server to force a 503 response on all requests to the cache-server and
the origin server end-points.  We can then count the number of connection
requests that `gvfs-helper` makes to the server and confirm both the
per-server retries and whether fallback was attempted.

Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
- sign using Azure-stored certificates & client
- sign on Windows agent via python script
- job skipped if credentials for accessing certificate aren't present

Co-authored-by: Lessley Dennington <ldennington@github.com>
Co-authored-by: Sverre Johansen <sverre.johansen@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
By default, GVFS Protocol-enabled Scalar clones will fall back to the
origin server if there is a network issue with the cache servers.
However (and especially for the prefetch endpoint) this may be a very
expensive operation for the origin server, leading to the user being
throttled. This shows up later in cases such as 'git push' or other web
operations.

To avoid this, create a new config option, 'gvfs.fallback', which
defaults to true. When set to 'false', pass '--no-fallback' from the
gvfs-helper client to the child gvfs-helper server process.

This will allow users who have hit this problem to avoid it in the
future. In case this becomes a more widespread problem, engineering
systems can enable the config option more broadly.

Enabling the config will of course lead to immediate failures for users,
but at least that will help diagnose the problem when it occurs instead
of later when the throttling shows up and the server load has already
passed, damage done.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
- create release & uploads artifact using Octokit
- use job "if" condition to handle uploading signed *or* unsigned .deb

Co-authored-by: Lessley Dennington <ldennington@github.com>
Update `git archive` tree-ish argument from `HEAD^{tree}` to `HEAD`. By
using a commit (rather than tree) reference, the commit hash will be stored
as an extended pax header, extractable git `git get-tar-commit-id`.

The intended use-case for this change is building `git` from the output of
`make dist` - in combination with the ability to specify a fallback
`GIT_BUILT_FROM_COMMIT`, a user can extract the commit ID used to build the
archive and set it as `GIT_BUILT_FROM_COMMIT`. The result is fully-populated
information for the commit hash in `git version --build-options`.

Signed-off-by: Victoria Dye <vdye@github.com>
It is possible that a loose object that is written from a GVFS protocol
"get object" request does not match the expected hash. Error out in this
case.

2021-10-30: The prototype for read_loose_object() changed in 31deb28 (fsck:
don't hard die on invalid object types, 2021-10-01) and 96e41f5 (fsck:
report invalid object type-path combinations, 2021-10-01).

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
When we create temp files for downloading packs, we use a name
based on the current timestamp. There is no randomness in the
name, so we can have collisions in the same second.

Retry the temp pack names using a new "-<retry>" suffix to the
name before the ".temp".

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Add "mayhem" keys to generate corrupt packfiles and/or corrupt idx
files in prefetch by trashing the trailing checksum SHA.

Add unit tests to t5799 to verify that `gvfs-helper` detects these
corrupt pack/idx files.

Currently, only the (bad-pack, no-idx) case is correctly detected,
Because `gvfs-helper` needs to locally compute the idx file itself.

A test for the (bad-pack, any-idx) case was also added (as a known
breakage) because `gvfs-helper` assumes that when the cache server
provides both, it doesn't need to verify them.  We will fix that
assumption in the next commit.

Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
Create new `cache_http_503` mayhem method where only the cache server
sends a 503.  The normal `http_503` directs both cache and origin
server to send 503s.  This will be used to help test fallback.

Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
It really does not make sense to run that workflow in any fork of
git-for-windows/git. Typically, it is enough to simply disable it (since
it is a scheduled workflow, it is disabled by default in any new fork).

However, in microsoft/git, we switch the default branch whenever we
rebase to a new upstream version, and every time we do so, this
scheduled workflow gets re-enabled.

Let's just delete it in microsoft/git and never be bothered by it again.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Update build-git-installers workflow to publish `microsoft/git`'s GPG public
key as part of each release. Add explanation for how to use this key to verify
the Debian package's signature to the README.
Set the `GIT_BUILT_FROM_COMMIT` based on the version specified in the `make
dist` output archive header. This ensures the commit hash is shown in
`git version --build-options`.

Signed-off-by: Victoria Dye <vdye@github.com>
Teach helper/test-gvfs-protocol to be able to send corrupted
loose blobs.

Add unit test for gvfs-helper to detect receipt of a corrupted loose blob.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
`sparse` complains with an error message like this:

	gvfs-helper.c:2912:17: error: expression using sizeof on a
	function

The culprit is this line:

	curl_easy_setopt(slot->curl, CURLOPT_WRITEFUNCTION, fwrite);

Similar lines exist in `http-push.c` and other files that are in
upstream Git, and to avoid these bogus warnings, they are already
exempted from `sparse`'s tender, loving care. We simply add
`gvfs-helper.c` to that list.

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
The GVFS cache server can return multiple pairs of (.pack, .idx)
files.  If both are provided, `gvfs-helper` assumes that they are
valid without any validation.  This might cause problems if the
.pack file is corrupt inside the data stream.  (This might happen
if the cache server sends extra unexpected STDERR data or if the
.pack file is corrupt on the cache server's disk.)

All of the .pack file verification logic is already contained
within `git index-pack`, so let's ignore the .idx from the data
stream and force compute it.

This defeats the purpose of some of the data cacheing on the cache
server, but safety is more important.

Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
For Scalar and VFS for Git, we use an alternate as a shared object
cache. We need to enable the maintenance builtin to work on that
shared object cache, especially in the background.

'scalar run <task>' would set GIT_OBJECT_DIRECTORY to handle this.

We set GIT_OBJECT_DIRECTORY based on the gvfs.sharedCache config,
but we also need the checks in pack_loose() to look at that object
directory instead of the current ODB's.

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
When the virtualfilesystem is enabled the previous implementation of
clear_ce_flags would iterate all of the cache entries and query whether
each one is in the virtual filesystem to determine whether to clear one
of the SKIP_WORKTREE bits. For each cache entry, we would do a hash
lookup for each parent directory in the is_included_in_virtualfilesystem
function.

The former approach is slow for a typical Windows OS enlistment with
3 million files where only a small percentage is in the virtual
filesystem. The cost is
O(n_index_entries * n_chars_per_path * n_parent_directories_per_path).

In this change, we use the same approach as apply_virtualfilesystem,
which iterates the set of entries in the virtualfilesystem and searches
in the cache for the corresponding entries in order to clear their
flags. This approach has a cost of
O(n_virtual_filesystem_entries * n_chars_per_path * log(n_index_entries)).

The apply_virtualfilesystem code was refactored a bit and modified to
clear flags for all names that 'alias' a given virtual filesystem name
when ignore_case is set.

n_virtual_filesystem_entries is typically much less than
n_index_entries, in which case the new approach is much faster. We wind
up building the name hash for the index, but this occurs quickly thanks
to the multi-threading.

Signed-off-by: Neeraj Singh <neerajsi@ntdev.microsoft.com>
This was disabled by a0da6de (ci: only run win+VS build & tests in
Git for Windows' fork, 2022-12-19) to avoid other forks doing too many
builds. But we want to keep these builds for the microsoft/git fork.

Signed-off-by: Derrick Stolee <derrickstolee@github.com>
For the same rationale as the preceding release-homebrew commit,
port the body of `.github/workflows/release-vfsforgit.yml` into a
POSIX-sh script that the operator invokes by hand while promoting a
pre-release to a full release. Given a release tag on microsoft/git,
the script opens a pull request against microsoft/VFSForGit that
bumps the `GIT_VERSION` default in `.github/workflows/build.yaml` so
that VFSForGit builds pick up the newly promoted release by default.

The operator's own `gh auth login` session already has push access
to microsoft/VFSForGit, so no PAT and no Key Vault-backed secret are
needed. The commit and the pull request are attributed to that user
rather than to `github-actions[bot]`, which also makes the change to
the downstream repository traceable to an identifiable human who can
be pinged for follow-up.

One portability wart worth calling out: the version bump uses the
`<in >out && mv -f out in` idiom rather than `sed -i`, because the
`-i` flag has incompatible spellings between GNU sed on Linux (which
accepts `-i` with no argument) and BSD sed on macOS (which requires
an explicit empty suffix, `-i ''`). The script is expected to run
from either platform, so it sticks to the portable form and stays
plain POSIX sh throughout.

Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
…d-port of #915) (#921)

Forward-port of #915 ("checkout: preserve skip-worktree for virtual
filesystem paths", merged into `vfs-2.53.0` as ea3eb21) to
`vfs-2.54.0`.

Cherry-picked from the underlying PR-branch commit
d40f13b (so the original
well-crafted commit message and Tyrie Vella's authorship are preserved).
One auto-merge in `builtin/checkout.c` resolved cleanly without
conflicts.
Same rationale as the two prior scripts (release-homebrew.sh,
release-vfsforgit.sh): replace a CI-driven fan-out step with a
hand-run script that reads its GitHub token from `gh auth token`,
sidestepping the PAT/Azure Key Vault dance.

This one _must_ be run on Windows (or in WSL) because
`wingetcreate.exe`, the tool that authors the manifest and opens
the PR against microsoft/winget-pkgs, is Windows-only; the
superseded workflow already ran on `windows-latest` for that
reason, and neither the operator nor the automation ever invoked
this step from macOS or Linux.

microsoft/git tags look like `vX.Y.Z.vfs.N.M`, but winget wants a
purely dotted numeric version, so the script strips the leading
`v` and the `vfs.` segment to produce `X.Y.Z.N.M` (for example,
`v2.54.0.vfs.0.4` becomes `2.54.0.0.4`), matching what the
previous workflow emitted.

The tag is parsed with `-not ($tag -match ...)` rather than the
seemingly equivalent `-notmatch`, because PowerShell's `-notmatch`
operator does not populate the `$Matches` automatic variable, yet
the two capture groups are read as `$Matches[1]` and `$Matches[2]`
immediately afterwards. See
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_comparison_operators
for the documented behaviour.

`wingetcreate submit` pushes to the operator's personal fork of
microsoft/winget-pkgs and opens a PR from there; if that fork is
stale, submit fails with "The forked repository could not be
synced". The script therefore issues a
`POST /repos/<user>/winget-pkgs/merge-upstream` first, and treats
a 404 as fine, since wingetcreate creates the fork on demand at
submit time when none exists.

Assisted-by: Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The Windows runners used by `vfs-functional-tests.yml` ship `rustup`
plus a `*-pc-windows-msvc` default toolchain (see
https://github.com/actions/runner-images/blob/main/images/windows/Windows2022-Readme.md
and
https://github.com/actions/partner-runner-images/blob/main/images/arm-windows-11-image.md),
but no precompiled `std` for `*-pc-windows-gnu` or
`*-pc-windows-gnullvm`. With the Makefile now picking a
GCC-compatible target triple based on `$(MSYSTEM)`, the build step
needs that precompiled `std` to be installed before invoking `make`,
otherwise `cargo build --target <triple>` fails to find a usable
`std` for the chosen target.

Add a step between the SDK setup and the `make` invocation that
selects the matching triple from `$MSYSTEM` (which
`git-for-windows/setup-git-for-windows-sdk` exports for every
subsequent step) and runs `rustup target add` for it. The mapping
mirrors what `config.mak.uname` derives from `$(MSYSTEM)` and
`$(HOST_CPU)`, just enumerated explicitly here since CI has direct
knowledge of which MSYS2 subsystems the matrix actually exercises
(`CLANGARM64` for the ARM64 runner, `MINGW64` for the x86_64
runner).

For a `staticlib` crate-type `cargo build` does not invoke an
external linker, so no further toolchain components (e.g. the
`gnullvm` LLVM linker) need to be installed; `rustup target add`
alone is sufficient.

Assisted-by: Claude Opus 4.7
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Some users reported issues of repeated messages:

  fatal: recursion detected in die handler

This wasn't happening every time, but we eventually captured a
GIT_TRACE2_PERF log file with this issue and revealed an interesting
internal detail, failing with this message:

  unable to format message: %4d-%02d-%02dT%02d:%02d:%02d.%06ldZ

This specific format string tracks to tr2_tbuf_utc_datetime_extended()
in trace2/tr2_tbuf.c. This logic began as tr2_tbuf_utc_time() in
ee4512e (trace2: create new combined trace facility, 2019-02-22) but
was later split in bad229a (trace2: clarify UTC datetime formatting,
2019-04-15).

This use of xsnprintf() is writing a very specific datetime format into a
32-character buffer. The format requires that the input data will not
overflow the format digits or the buffer will not hold the result. Since
we are using xsnprintf() here, those failures turn into die() events.

This method and its siblings, tr2_tbuf_local_time() and
tr2_tbuf_utc_datetime(), are used in the tracing library. The extended
form is used only for the 'event' format, which these users were using
via a config setting for use in client-side telemetry. The non-extended
form is used to help generate the 'SID' that defines the process in the
traces.

Not only are these inappropriate times for a failure, but the extended
method is called specifially during the 'atexit' event, which was
triggering this problem in a loop as the 'atexit' event would be
retriggered by the die().

I could not determine the exact cause of why these errors started
occuring in a bunch. My best guess is that these users are dogfooding an
early operating system version that is more likely to fail in the
gettimeofday() function and thus leaves the structures uninitialized and
potentially violating the expected values.

However, for full defense-in-depth I made several modifications:

1. Both 'tv' and 'tm' structs are initialized with zero values, allowing
   an erroring gettimeofday() or gmtime_r() method to leave them
   zero-valued. A zero-valued date is better than a die() here.

2. Replace the use of xsnprintf() with snprintf() to avoid the
   possibility of calling die() here. Instead, check the response to see
   if there was a failure. On failure, put a blank value into the buffer
   instead of possibly allowing a value that would not format correctly
   for a trace2 consumer. This value should be seen as obviously wrong
   and therefore signals a problem.

As the core issue in this code seems to require a system method
returning an error, no test accompanies this change.

This change removes all uses of xsnprintf() from the trace2/ directory.
There are two uses of xstrdup() that could be considered for removal,
but they only die() on out-of-memory errors instead of formatting
issues. I chose to leave those in place for now.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
This PR simply ports #952 to the `vfs-2.55.0` branch.

It intentionally collapses the commits to make future rebases quicker.
In virtual filesystem (VFS/GVFS) mode, reset --mixed failed to report
hydrated files as modified. A hydrated file is one that has been read
(e.g. via blame or cat-file) and materialized on disk by ProjFS, but
not modified — so it is not in GVFS's ModifiedPaths database and
retains the skip-worktree bit in the index.

The existing VFS-specific code in update_index_from_diff() used
file_exists() to decide whether to clear skip-worktree:

  - Files NOT on disk (virtual/placeholder): file_exists() returns
    false, skip-worktree is cleared, and the pre-reset content is
    written to disk via checkout_entry(). These files correctly
    appear as modified. This path remains unchanged.

  - Files already on disk (hydrated): file_exists() returns true,
    so the code left skip-worktree set. refresh_index() then skipped
    the file entirely, hiding the working-tree vs index mismatch.
    The file was invisible to both the reset output and subsequent
    git status.

Fix this by always clearing skip-worktree (respect_skip_worktree = 0)
for all entries processed by update_index_from_diff() when VFS mode is
active. The file_exists() check now only controls whether pre-reset
content needs to be written to disk — it no longer affects the
skip-worktree decision.

After the reset, GVFS's GitIndexParser detects the cleared
skip-worktree bits via the post-index-change hook and adds the
affected paths to ModifiedPaths, so subsequent git commands also
see them correctly.

Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Users were noticing some cases of infinite loops with the error message:

```
fatal: recursion detected in die handler
```

It's only happening for repos with a post-command hook, but it's not
deterministic. I'm not sure what is triggering the problem, but the
post-command hook is definitely able to recurse with its existing logic
around the `run_post_hook` variable.

Move this earlier to avoid a potential double-call. It's a fixup to the
introduction of the method, which may cause conflicts with later
adjustments to this method still in the branch thicket (but maybe those
should be squashed, too).

See #955 for the version on 2.54.0.
When pushing from a repository that uses the GVFS Protocol, `git push`
spawns `git pack-objects --all-progress-implied --revs --stdout --thin
-q` and feeds it revision parameters on stdin: the advertised refs and
negotiated objects as negative (exclusion) tips, plus each ref's old and
new tips. Normally feed_object() omits a negative object that is not
present locally, but the core.gvfs GVFS_MISSING_OK bit disables that
check so that missing negatives are still fed.

That bypass is actively harmful under the GVFS Protocol. pack-objects
adds `--objects-edge` for `--thin` and, while marking edges
uninteresting and hunting for preferred delta bases, reads the tree of
every fed exclusion. For an exclusion the client does not have locally,
that read lazily downloads the object, issuing one gh_client__get_
immediate request per advertised ref. A scalar clone against a server
that advertises many refs therefore triggers a storm of immediate object
fetches during an ordinary push.

Partial clone deliberately assumes the objects behind our refs are
already present and never fetches them for a push. Restore that behavior
for the GVFS Protocol behind a new opt-in config, gvfs.negativeRefCheck.
When set, `git push` performs a non-fetching existence check --
odb_has_object() with flags 0 implies OBJECT_INFO_QUICK |
OBJECT_INFO_SKIP_FETCH_OBJECT, so the probe never fetches -- and omits
any advertised object it does not have, exactly as Git does without the
GVFS_MISSING_OK bit. The decision is computed once in pack_objects()
because advertised ref lists can be large.

The config defaults to false, so the legacy GVFS_MISSING_OK behavior is
unchanged unless an operator opts in, keeping the fallout controllable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
#963)

This is a companion of #935, porting the changes from vfs-2.54.0 to
vfs-2.55.0.

## Problem

In virtual filesystem (VFS/GVFS) mode, `reset --mixed` fails to report
hydrated files as modified.

A **hydrated file** is one that has been read (e.g., via `blame` or
`cat-file`) and materialized on disk by ProjFS, but not modified — so it
is not in GVFS's ModifiedPaths database and retains the `skip-worktree`
bit in the index.

### Reproduction

1. `gvfs clone` a repo
2. `git blame Readme.md` — hydrates the file (ProjFS materializes
content on disk)
3. `git reset --mixed HEAD~1` (where `Readme.md` differs between HEAD
and HEAD~1)
4. **Expected:** `Readme.md` appears in reset output and `git status`
shows it as modified
5. **Actual:** `Readme.md` is missing from output; `git status` reports
clean

### Root cause

The VFS-specific code in `update_index_from_diff()` uses `file_exists()`
to decide whether to clear `skip-worktree`:

- **Files NOT on disk** (virtual/placeholder): `file_exists()` returns
false → `skip-worktree` cleared, pre-reset content written to disk via
`checkout_entry()` → correctly reported as modified ✓
- **Files on disk** (hydrated): `file_exists()` returns true →
`skip-worktree` left set → `refresh_index()` skips the entry → invisible
to status ✗

The original code assumed that if a file exists on disk, it must already
be tracked properly. But hydrated-but-not-modified files exist on disk
with stale content and are NOT in ModifiedPaths.

## Fix

Always clear `skip-worktree` (`respect_skip_worktree = 0`) for all
entries processed by `update_index_from_diff()` when VFS mode is active.
The `file_exists()` check now only controls whether pre-reset content
needs to be written to disk — it no longer gates the skip-worktree
decision.

After the reset, GVFS's `GitIndexParser` detects the cleared
skip-worktree bits via the `post-index-change` hook and adds affected
paths to ModifiedPaths, so subsequent git commands also see them
correctly.

### Before (buggy)
```c
if (core_virtualfilesystem && !file_exists(two->path))
{
    respect_skip_worktree = 0;      // only for missing files
    // ... write content to disk ...
}
```

### After (fixed)
```c
if (core_virtualfilesystem)
{
    respect_skip_worktree = 0;      // for ALL changed entries

    if (!file_exists(two->path))    // only write content for missing files
    {
        // ... write content to disk ...
    }
}
```

## Testing

- 3 new tests in `t1093-virtualfilesystem.sh`:
- **Hydrated file**: file exists on disk, should appear in reset output
- **Non-hydrated file**: file missing from disk, should be written and
appear in output
  - **Partial reset**: unchanged files retain skip-worktree
- Verified manually against a real GVFS enlistment: GVFS and control
repo now produce identical output (224 modified files including
`Readme.md`)
- All 25 existing `t1093` tests pass
When using the GVFS protocol with 'scalar clone', the first 'git fetch'
uses the prefetch endpoint to download commits and trees so history
operations are usable immediately after cloning.

Some users want to optimize for the initial usability of the repository,
and they don't need the full history available right away. They are
prepared to wait for future fetches (perhaps in the background) doing
that work for them.

Add a new --no-prefetch option that skips the initial prefetch. This is
implemented by using '-c core.gvfs=X' arguments in the underlying fetch
operation to temporarily avoid the prefetch operation for that
subcommand only.

It's important that this does not actually stop prefetches forever,
though that can be adjusted by flipping the appropriate bit in the
core.gvfs config option.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
The object database refactor that introduced per-source object stores
(cb506a8 "odb: introduce \"files\" source" and the surrounding series,
first released in v2.54.0) changed how do_oid_object_info_extended()
searches for an object. It now iterates the sources and, within each
source, consults that source's packfiles and then its loose object
store before moving on to the next source.

Before that series the search consulted every packfile -- across the
primary object directory and all alternates -- before it looked at any
loose object. The refactor reversed that for the multi-source case:
for an object that lives in an alternate's packfile, the primary
source's loose object store is now consulted first. That loose lookup
is a filesystem stat(), and because callers such as
cache_tree_fully_valid() pass ODB_HAS_OBJECT_RECHECK_PACKED (which
clears OBJECT_INFO_QUICK) the cached-loose-index fast path is skipped
and a real stat() runs for every such object.

In a repository that keeps its objects in an alternate -- the common
arrangement for VFS for Git and Scalar enlistments, where a shared
object cache is mounted as an alternate -- this is a steep penalty.
cache_tree_fully_valid() walks the whole cache tree and calls
odb_has_object() for every node; on an enlistment with a ~2.4M-entry
index that is ~380k objects, each incurring a wasted stat() on the
primary loose store. A same-commit branch switch spent ~32s in
cache_tree_fully_valid() (two calls of ~16s), observed in the field as
a ~2x rise in median checkout duration after the client carrying the
refactor rolled out.

Restore the previous ordering without undoing the per-source
encapsulation: when there is more than one source, scan the packfiles
of every source first (OBJECT_INFO_SKIP_LOOSE) and only then consult
each source's loose store (OBJECT_INFO_SKIP_PACKED). The single-source
case is unchanged, so repositories without alternates keep the
existing path. With the fix the same branch switch spends ~2s in
cache_tree_fully_valid(), the ~380k wasted stat()s are gone, and
performance matches versions predating the refactor.

Assisted-by: Claude Opus 4.8
Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
When pushing from a repository that uses the GVFS Protocol, `git push`
spawns `git pack-objects --all-progress-implied --revs --stdout --thin
-q` and feeds it revision parameters on stdin: the advertised refs and
negotiated objects as negative (exclusion) tips, plus each ref's old and
new tips. Normally feed_object() omits a negative object that is not
present locally, but the core.gvfs GVFS_MISSING_OK bit disables that
check so that missing negatives are still fed.

That bypass is actively harmful under the GVFS Protocol. pack-objects
adds `--objects-edge` for `--thin` and, while marking edges
uninteresting and hunting for preferred delta bases, reads the tree of
every fed exclusion. For an exclusion the client does not have locally,
that read lazily downloads the object, issuing one gh_client__get_
immediate request per advertised ref. A scalar clone against a server
that advertises many refs therefore triggers a storm of immediate object
fetches during an ordinary push.

Partial clone deliberately assumes the objects behind our refs are
already present and never fetches them for a push. Restore that behavior
for the GVFS Protocol behind a new opt-in config, gvfs.negativeRefCheck.
When set, `git push` performs a non-fetching existence check --
odb_has_object() with flags 0 implies OBJECT_INFO_QUICK |
OBJECT_INFO_SKIP_FETCH_OBJECT, so the probe never fetches -- and omits
any advertised object it does not have, exactly as Git does without the
GVFS_MISSING_OK bit. The decision is computed once in pack_objects()
because advertised ref lists can be large.

The config defaults to false, so the legacy GVFS_MISSING_OK behavior is
unchanged unless an operator opts in, keeping the fallout controllable.

* [X] This change only applies to interactions with Azure DevOps and the
      GVFS Protocol.
Prepare the configuration surface for parallel POST workers before the
worker implementation is introduced. Add gvfs.postThreads with a default
of one so this commit does not change request execution on its own.

Document the intended concurrent behavior and clamp values below one.
Later commits in the series consume the value while introducing the
parallel success path and then its complete failure handling.

Helped-by: GPT-5.6 Sol
Co-authored-by: Neil Kainga <t-neilkainga@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Neil Kainga <t-neilkainga@microsoft.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
When a user uses the --no-prefetch option, they do not get batched
commit and tree packfiles before attempting a checkout. Thankfully, the
GVFS Protocol has a mechanism to help here: the /gvfs/objects POST
endpoint can ask for a commit and that will trigger a download of all
trees needed for a checkout of that commit.

When using --no-prefetch and the GVFS protocol, run this extra POST
request before running a checkout.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
Switching branches in a VFS for Git or Scalar enlistment became drastically
slower in Git v2.55. The cause is the interaction of two independent changes,
not a single one.

Commit 062b914 (treewide: convert users of repo_has_object_file() to
has_object()), first released in v2.50, accidentally inverted the object
existence check in cache_tree_fully_valid(), so that function bailed out at the
root instead of validating the cache tree recursively. Commit 5217312
(cache-tree: fix inverted object existence check in cache_tree_fully_valid),
first released in v2.55, correctly restored the recursion.

In between, v2.54's per-source object database refactor changed the
cross-source lookup order: instead of scanning all packfiles before any loose
object store, it scans packed then loose per source. That change caused no
observable checkout regression in v2.54 precisely because the inverted check
prevented recursion and thereby masked the per-object cost. Conversely, v2.49
did recurse, yet stayed fast because its global pack-first lookup found the
objects in an alternate's packs before attempting any loose lookup. v2.55 is
therefore the first version combining recursive cache-tree validation with
per-source packed-then-loose lookup, at a cost of roughly one wasted primary
loose-object lstat() per cache-tree node.

In enlistments that use an alternate object cache, that cost is severe.
cache_tree_fully_valid() calls odb_has_object() hundreds of thousands of times,
and ODB_HAS_OBJECT_RECHECK_PACKED clears OBJECT_INFO_QUICK, so each call
performs a real lstat() in the primary loose object store before the object is
found in the alternate's packfile. On a measured index with about 2.4M entries:
381,006 cache-tree nodes, 380,944 wasted lstat() calls, not a single miss;
cache-tree validation took about 32 seconds and switching to a branch pointing
at the same commit about 36 seconds.

This merge restores the all-sources-packed-before-all-sources-loose order
whenever more than one source is present. The wasted stats are gone, validation
drops to about 2 seconds and branch switching to about 6-7 seconds. Presence
semantics are unchanged.

The trade-off needs to be stated plainly: the mitigation lives in the shared
object-info lookup, which is a slightly incorrect representation layer for a
problem specific to presence-only queries via odb_has_object(). When an object
is loose in the primary and packed in an alternate, metadata callers now
observe the alternate's packed representation. Observable differences include
reported on-disk size, mtime, delta base, corruption handling, and
promisor-pack classification. Object content, type and logical size, as well as
presence, remain correct because objects are content-addressed, which bounds
the fallout to the representation level. We accept those behavior changes
deliberately in exchange for fixing an intolerable regression in this fork now.

The architecturally correct fix is upstream's plan to move alternate handling
into the files backend. That backend would own both the primary and the
alternates and could therefore scan all relevant packs before any loose-object
lookup without violating the abstraction. The upstream contributor estimates
that work at "three to four patch years", i.e. likely months in Git project
time, and probably not before Git 2.56. microsoft/git cannot wait that long.

This merge is consequently an explicitly temporary mitigation specific to
Microsoft Git. Once upstream's fix lands, this implementation should be
replaced and the regression test reassessed. That test currently asserts
packed-versus-loose selection through %(deltabase), which necessarily pins
representation ordering and may not survive the upstream architecture. A future
replacement could instead verify the absence of the unwanted lstat() calls
directly, possibly as a Linux-only strace test, since the behavior itself is
platform-independent.
The parallel POST implementation needs standalone curl handles with the
same runtime settings as handles allocated through get_active_slot().
Creating raw handles would otherwise omit cookies, configured host
resolutions, redirect policy, IP selection, and current authentication
defaults.

Extract the per-request handle preparation into a shared helper and use
it from get_active_slot(). Expose a function that duplicates the
initialized default handle and applies the same preparation for callers
that manage a handle outside the active-slot machinery.

Also expose whether cookies are configured. Libcurl cannot safely share
cookie state across concurrently performing handles, so callers can
retain an established sequential path in that case.

Helped-by: GPT-5.6 Sol
Co-authored-by: Neil Kainga <t-neilkainga@microsoft.com>
Signed-off-by: Neil Kainga <t-neilkainga@microsoft.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
When using the GVFS protocol with `scalar clone`, the first `git fetch`
issues a `/gvfs/prefetch` request to download the commits and trees that
back the checked-out branch, so history operations are usable
immediately
after cloning. For large repositories this prefetch can dominate the
clone
time.

Some users would rather optimize for the initial usability of the
working
tree and do not need full history right away; they are content to let a
later fetch (including background maintenance) download the prefetch
data
for them.

This PR adds a `--[no-]prefetch` option to `scalar clone`. With
`--no-prefetch`, the initial `/gvfs/prefetch` request is skipped so the
worktree becomes ready as quickly as possible.

### Implementation

The prefetch-during-fetch behavior is gated by the
`GVFS_PREFETCH_DURING_FETCH`
bit (`1 << 7`) in `core.gvfs`, which `scalar clone` sets as part of the
value `150`. Rather than persisting a different `core.gvfs` value (which
would disable prefetching *forever*), `--no-prefetch` only clears that
bit
for the single `git fetch` invocation performed during the clone, by
passing `-c core.gvfs=<value without the prefetch bit>`.

The persisted `core.gvfs` is left untouched, so:

- the initial clone skips the prefetch and finishes sooner, and
- the **next** `git fetch` -- including the background maintenance
  `prefetch` task -- still performs the prefetch, hydrating the object
  cache shortly afterward.

The option has no effect when the GVFS Protocol is not in use.

### Documentation

`Documentation/scalar.adoc` documents `--[no-]prefetch`, making clear
that
it only affects the clone's initial fetch and that the prefetch data is
still downloaded by the next fetch.

### Tests

`t/t9210-scalar.sh` gains a test against the GVFS-enabled test server
which
asserts that:

- a normal clone emits a `prefetch/since` trace event,
- a `--no-prefetch` clone does not,
- the persisted `core.gvfs` remains `150`, and
- a subsequent `git fetch` performs the deferred prefetch.
Fetching a large set of missing objects through gvfs-helper performs
each HTTP POST and index-pack operation sequentially. This leaves the
client waiting on individual network transfers even when the server and
local machine can support concurrent work.

Introduce the parallel success-path mechanism. Use a mutex-protected
queue to distribute full object batches across worker threads. Each
worker owns a curl handle and streams each response into a fresh
index-pack process.

Serialize child startup while marking pipe descriptors close-on-exec so
concurrent index-pack children cannot keep sibling pipes open. Keep OID
formatting and result collection thread-local, and partition work into
batches containing at least two objects because a single non-commit
object can be returned loose instead of as a pack.

This commit deliberately establishes the core worker and transfer
mechanics first. The next commit completes authentication, throttling,
fallback, retry, and concurrent pack installation behavior before tests
exercise the new path.

Helped-by: GPT-5.6 Sol
Co-authored-by: Neil Kainga <t-neilkainga@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Neil Kainga <t-neilkainga@microsoft.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Since f978f56 (odb: eagerly initialize alternates, 2026-08-17),
config-only commands emit error-labelled diagnostics for unusable
alternates even though those entries are ignored. An unset config key
still returns the ordinary status 1, but VFS mistakes the accompanying
diagnostics for a configuration failure and cannot recreate a deleted
shared cache.

Warnings keep these diagnostics visible without implying that ignoring
an alternate is a command failure, and VFS already tolerates them. The
message text and source rejection behavior remain unchanged.

Assisted-by: GPT-6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The initial parallel POST path handles successful requests but does not
yet match the sequential path when authentication, throttling, corrupt
responses, or concurrent pack installation interfere with a request.
Those differences can turn recoverable network failures into hard
errors or allow sibling processes to manipulate the same pack paths.

Classify HTTP and curl failures with the existing retry rules, refresh
credentials outside worker threads, and preserve the cache, backup
cache, and origin fallback order. Share response-header parsing with the
sequential path so workers retain rate-limit telemetry while keeping
soft-throttle state local to each worker.

Coordinate Retry-After delays across workers without overflowing sleep
intervals, and wait before starting index-pack. Serialize child setup and
completion because finish_command() invalidates process-global path
state. Limit the worker count to the number of queued object batches.

Give each index-pack attempt unique pack and index paths, validate its
reported pack hash, and retry corrupt or truncated responses. A complete
final pack and index pair remains sufficient when another process wins
the installation race.

Group the per-attempt buffers behind one cleanup helper so success,
retry, fallback, and failure paths release the same state.

Helped-by: GPT-5.6 Sol
Co-authored-by: Neil Kainga <t-neilkainga@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Neil Kainga <t-neilkainga@microsoft.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
A VS x64 build linked scalar successfully, then its post-build
vcpkg.exe z-applocal invocation failed with "The process cannot access
the file because it is being used by another process." MSBuild reported
exit 32.

https://github.com/microsoft/git/actions/runs/35200873703

In vcpkg 2026-07-27, the telemetry self-copy can open the tool's executable
without sharing (src/vcpkg/base/files.cpp:3757-3832), outside the DLL
deployment mutex. That can prevent concurrent launches with the same
diagnostic and exit status, although the CI lock owner was not recorded.

Avoid this source of contention by disabling unnecessary telemetry for
MSBuild, retaining native app-local DLL deployment and four workers.

Assisted-by: GPT-6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Exercise gvfs-helper POST requests with both one and four configured
workers so the sequential and parallel paths must fetch identical object
sets. Cover multiple batches, a final single-OID remainder, and duplicate
requests while checking both installed objects and packfile counts.

Require pthread support for parallel cases and use Trace2 assertions to
prove that each test reaches its intended execution mode.

Helped-by: GPT-5.6 Sol
Co-authored-by: Neil Kainga <t-neilkainga@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Neil Kainga <t-neilkainga@microsoft.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
Cargo's MSVC builds need Microsoft's `link.exe` to take precedence.
41d1d14 (rust: fix linking binaries with cargo) assumes
`/mingw64/bin`, so `/ucrt64/bin` can remain ahead of MSVC in `PATH`.

Honor the active MinGW environment, including SDK setups that provide
`MSYSTEM` rather than `MINGW_PREFIX`. Use the modern UCRT64 default
when neither is set, while explicit `MSYSTEM=MINGW64` or
`MINGW_PREFIX=/mingw64` settings continue to select the legacy toolchain.

Assisted-by: GPT-6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Parallel requests need to preserve the sequential path's behavior for
configuration boundaries, authentication, throttling, cache fallback,
corrupt responses, and request headers.

Extend the protocol test server with targeted failure modes. Verify that
parallel POST refreshes authentication, honors Retry-After, falls back
from cache 404 responses only when permitted, retries a one-time corrupt
pack, and reports permanent corruption as an index-pack failure.

Also cover absent and invalid thread configuration, cookie-enabled
sequential fallback, configured headers, multiple participating workers,
and a timeout-protected child-pipe stress case.

Helped-by: GPT-5.6 Sol
Co-authored-by: Neil Kainga <t-neilkainga@microsoft.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Signed-off-by: Neil Kainga <t-neilkainga@microsoft.com>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
CMake's x64 build definitions already select UCRT64, but the runtime
fallback still assumes `/mingw64`. Match the existing defaults when
`system_prefix()` cannot infer the prefix from the executable location.
Normal discovery and explicit architecture definitions remain unchanged.

Assisted-by: GPT-6
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Improve full-clone performance by allowing `gvfs-helper post` to
download
object batches concurrently. The new `gvfs.postThreads` configuration
defaults to 1, preserving the existing sequential behavior unless
explicitly
enabled.

The series is organized into six reviewable commits:

1. Add the configuration surface.
2. Factor reusable curl-handle preparation.
3. Introduce the parallel POST success path.
4. Complete retry, authentication, fallback, throttling, and pack
   installation behavior.
5. Test sequential and parallel success paths.
6. Test failure handling and request-header parity.

Each worker owns an independently prepared curl handle and streams
responses
into a dedicated `index-pack --stdin` child. Work is distributed through
a
mutex-protected queue, with the worker count capped by the number of
object
batches. Requests with configured cookies retain the established
sequential
path because libcurl cookie state cannot safely be shared by
concurrently
performing handles.

The parallel path preserves the sequential HTTP policy for
authentication
refresh, transient errors, Retry-After, cache and backup-cache fallback,
`--no-fallback`, configured headers, `X-Session-Id`, and `X-VSS-E2EID`.
Sequential and parallel requests share response-header parsing, while
soft-throttle state remains local to each worker.

Child pipes are created and marked close-on-exec before spawning, and
child
setup and completion are serialized around process-global run-command
state.
Each `index-pack` attempt uses unique pack and index paths, validates
its
reported pack hash, retries corrupt or truncated responses, and
tolerates
another process winning installation of the same final pack.

The focused `t5798-gvfs-helper-post-threads.sh` suite contains 22 tests
covering configuration boundaries, sequential and parallel requests,
multi-worker participation, singleton remainders, duplicate downloads,
deadlock prevention, authentication, throttling, cache fallback,
`--no-fallback`, corrupt packs, cookies, and configured headers.
Parallel
tests use pthread prerequisites and Trace2 assertions to prove the
intended
execution path.

Neil Kainga diagnosed and tested the pipe-inheritance fix on a 1JS full
clone
with `gvfs.postThreads=8` and is credited throughout the series.
@dscho
Johannes Schindelin (dscho) merged commit c81d6fd into vfs-2.56.0-rc2 Sep 23, 2026
167 checks passed
@dscho
Johannes Schindelin (dscho) deleted the tentative/vfs-2.56.0-rc2 branch September 23, 2026 10:05
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