Skip to content

Rebase to Git for Windows 2.56.0-rc1 - #990

Merged
Johannes Schindelin (dscho) merged 365 commits into
vfs-2.56.0-rc1from
tentative/vfs-2.56.0-rc1
Sep 23, 2026
Merged

Johannes Schindelin (dscho) merged 365 commits into
vfs-2.56.0-rc1from
tentative/vfs-2.56.0-rc1

Conversation

@dscho

Copy link
Copy Markdown
Member
Range-diff relative to clean/vfs-2.56.0-rc0
  • 2: 7500633 = 1: e8b6f68 t: remove advice from some tests

  • 6: 3bb63cd = 2: a837ddc survey: calculate more stats on refs

  • 34: a3c0958 = 3: d2d8b2b survey: show some commits/trees/blobs histograms

  • 35: 129f423 = 4: 4a763a5 survey: add vector of largest objects for various scaling dimensions

  • 36: 5f54bff = 5: 48f7678 survey: add pathname of blob or tree to large_item_vec

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

  • 43: 32e1bae = 7: bac7b8a fixup! ci(dockerized): do show the result of failing tests again

  • 38: 2c92909 = 8: 679d30d survey: add commit name-rev lookup to each large_item

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

  • 39: 964775a = 10: a10d5f5 survey: add --no-name-rev option

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

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

  • 40: 5766cd4 = 13: 8545e8f survey: started TODO list at bottom of source file

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

  • 1: 46eb66c = 15: 62dfe30 t5300: confirm failure of git index-pack when non-idx suffix requested

  • 33: 1c354c3 = 16: 4b6a062 t1092: add test for untracked files and directories

  • 41: 50dad10 = 17: 5d6b31e survey: expanded TODO list at the bottom of the source file

  • 47: 00e67bb = 18: 3e3cda8 fixup! survey: turn into a thin shim over git repo structure

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

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

  • 5: 931ef57 = 21: b6e9a10 trace2: prefetch value of GIT_TRACE2_DST_DEBUG at startup

  • 48: b10016d = 22: 4b3f05f reset --stdin: trim carriage return from the paths

  • 49: 9d4a892 ! 23: 2315267 Identify microsoft/git via a distinct version suffix

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

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

  • 52: ebc67af = 26: 6bb6cea gvfs: add the core.gvfs config setting

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

  • 119: b485a8f = 28: dad67c0 scalar: set the config write-lock timeout to 150ms

  • 120: cb011a7 = 29: 0e97b91 scalar: set the config write-lock timeout to 150ms

  • 121: 82c3d02 = 30: 6e5b9ce scalar: upgrade the config lock timeout setting automagically

  • 122: 11d1ee2 = 31: e3d9c2c config: (handle and) warn about deprecated lock timeout setting

  • 123: 8e34ab4 = 32: c6dcc7d scalar: add docs from microsoft/scalar

  • 124: dc68633 = 33: 48f662a scalar (Windows): use forward slashes as directory separators

  • 125: e08ee1e = 34: c836201 scalar: add retry logic to run_git()

  • 126: 1d0d6e5 = 35: 8eeb0de scalar: support the config command for backwards compatibility

  • 127: faac545 = 36: a9ee7c4 TO-UPSTREAM: sequencer: avoid progress when stderr is redirected

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

  • 8: d63a724 = 38: 2a33af0 fsck: avoid using an uninitialized variable

  • 9: a361fa5 = 39: 043d525 load_revindex_from_disk(): avoid accessing uninitialized data

  • 21: 4a57bae = 40: 975532c load_pack_mtimes_file(): avoid accessing uninitialized data

  • 10: 6588c6c = 41: 0dcf0ca revision: defensive programming

  • 11: ea5e631 = 42: 0d6ccdd get_parent(): defensive programming

  • 12: bd8de2b = 43: 80ee9af fetch-pack: defensive programming

  • 24: ddf80bb = 44: 3991a05 codeql: run static analysis as part of CI builds

  • 13: 6f8a428 = 45: 2625274 unparse_commit(): defensive programming

  • 25: 0b9521f = 46: bebfeea codeql: publish the sarif file as build artifact

  • 14: 7e7cb7c = 47: 8c0cfd6 verify_commit_graph(): defensive programming

  • 26: 3925ef3 = 48: 68098e0 codeql: disable a couple of non-critical queries for now

  • 15: 85c2ba1 = 49: 1002a1e stash: defensive programming

  • 27: 6287b25 = 50: a728598 date: help CodeQL understand that there are no leap-year issues here

  • 16: 18015c7 = 51: 8d99b7e stash: defensive programming

  • 28: b5bc320 = 52: 2c56230 help: help CodeQL understand that consuming envvars is okay here

  • 17: f1c57ea = 53: a591bf1 push: defensive programming

  • 29: de364d2 = 54: f539aa9 ctype: help CodeQL understand that sane_istest() does not access array past end

  • 18: 7de2e14 = 55: 63c78c3 test-tool repository: check return value of lookup_commit()

  • 19: ed03b01 = 56: d4d2bbb fetch: defensive programming

  • 30: 2929e38 = 57: 4647696 ctype: accommodate for CodeQL misinterpreting the z in mallocz()

  • 20: 476eec5 = 58: 8119da8 shallow: handle missing shallow commits gracefully

  • 22: e8e1878 = 59: b8d6506 inherit_tracking(): defensive programming

  • 31: 86dfdfd = 60: c5c7510 strbuf_read: help with CodeQL misunderstanding that strbuf_read() does NUL-terminate correctly

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

  • 32: 3d565bc = 62: 264244e codeql: also check JavaScript code

  • 54: 070e4e2 ! 63: bc828ac gvfs: add the feature that blobs may be missing

    @@ cache-tree.c
      #include "lockfile.h"
      #include "tree.h"
      #include "tree-walk.h"
    -@@ cache-tree.c: static int update_one(struct cache_tree *it,
    +@@ cache-tree.c: static int update_one(struct repository *repo,
      		      int flags)
      {
      	struct strbuf buffer;
     -	int missing_ok = flags & WRITE_TREE_MISSING_OK;
    -+	int missing_ok = gvfs_config_is_set(the_repository, GVFS_MISSING_OK) ?
    ++	int missing_ok = gvfs_config_is_set(repo, GVFS_MISSING_OK) ?
     +		WRITE_TREE_MISSING_OK : (flags & WRITE_TREE_MISSING_OK);
      	int dryrun = flags & WRITE_TREE_DRY_RUN;
      	int repair = flags & WRITE_TREE_REPAIR;
  • 55: 27a2466 = 64: efe7aac gvfs: prevent files to be deleted outside the sparse checkout

  • 56: ac9efbf = 65: 7cd8abe gvfs: optionally skip reachability checks/upload pack during fetch

  • 57: 552522f = 66: 9e059c1 gvfs: ensure all filters and EOL conversions are blocked

  • 58: 0effa7c ! 67: 936c3cb gvfs: allow "virtualizing" objects

    @@ odb.c: void disable_obj_read_lock(void)
     +	return ret;
     +}
     +
    - static int register_all_submodule_sources(struct object_database *odb)
    - {
    - 	int ret = odb->submodule_source_paths.nr;
    + static enum odb_read_status do_oid_object_info_extended(struct object_database *odb,
    + 							const struct object_id *oid,
    + 							struct object_info *oi, unsigned flags)
     @@ odb.c: static enum odb_read_status do_oid_object_info_extended(struct object_database *
      	enum odb_read_status ret;
      	int already_retried = 0;
    @@ odb.c: static enum odb_read_status do_oid_object_info_extended(struct object_dat
     +			}
      		}
      
    - 		/*
    + 		/* Check if it is a missing object */
  • 59: 697bc19 ! 68: 7078bf0 Hydrate missing loose objects in check_and_freshen()

    @@ odb.c: void disable_obj_read_lock(void)
     -	return ret;
     -}
     -
    - static int register_all_submodule_sources(struct object_database *odb)
    - {
    - 	int ret = odb->submodule_source_paths.nr;
    + static enum odb_read_status do_oid_object_info_extended(struct object_database *odb,
    + 							const struct object_id *oid,
    + 							struct object_info *oi, unsigned flags)
     @@ odb.c: static enum odb_read_status do_oid_object_info_extended(struct object_database *
      			}
      			if (gvfs_virtualize_objects(odb->repo) && !tried_hook) {
  • 60: d9f2b60 = 69: 52d65c3 sha1_file: when writing objects, skip the read_object_hook

  • 61: d513d64 = 70: 0db9709 gvfs: add global command pre and post hook procs

  • 62: 0af1253 = 71: cca50d8 t0400: verify that the hook is called correctly from a subdirectory

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

  • 64: c9cd2e0 = 73: 379801e Pass PID of git process to hooks.

  • 65: 6363a34 = 74: f27b308 sparse-checkout: make sure to update files with a modify/delete conflict

  • 66: 4d3b3a5 = 75: 5f08216 worktree: allow in Scalar repositories

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

  • 68: 53d1c52 = 77: 919aede Do not remove files outside the sparse-checkout

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

  • 70: d0e5d6b = 79: 14afb0c gvfs: allow corrupt objects to be re-downloaded

  • 71: 0c4f86d ! 80: df9d855 cache-tree: remove use of strbuf_addf in update_one

    @@ Commit message
         Signed-off-by: Kevin Willford <kewillf@microsoft.com>
     
      ## cache-tree.c ##
    -@@ cache-tree.c: static int update_one(struct cache_tree *it,
    +@@ cache-tree.c: static int update_one(struct repository *repo,
      			continue;
      
      		strbuf_grow(&buffer, entlen + 100);
    @@ cache-tree.c: static int update_one(struct cache_tree *it,
     +		}
     +		strbuf_add(&buffer, path + baselen, entlen);
     +		strbuf_addch(&buffer, '\0');
    - 		strbuf_add(&buffer, oid->hash, the_hash_algo->rawsz);
    + 		strbuf_add(&buffer, oid->hash, repo->hash_algo->rawsz);
      
      #if DEBUG_CACHE_TREE
  • 72: 71bdc1e = 81: d744a50 gvfs: block unsupported commands when running in a GVFS repo

  • 73: 03fd1e5 = 82: 5293057 gvfs: allow overriding core.gvfs

  • 74: b5641ef = 83: fe70f93 BRANCHES.md: Add explanation of branches and using forks

  • 75: 8c07328 = 84: e3dce25 Add virtual file system settings and hook proc

  • 76: 90e751b = 85: 155b7d1 virtualfilesystem: don't run the virtual file system hook if the index has been redirected

  • 77: 694a4b5 = 86: 71d3838 virtualfilesystem: check if directory is included

  • 78: 846ebaf = 87: 3b7e478 backwards-compatibility: support the post-indexchanged hook

  • 79: 41f89fd = 88: 6aa05b5 gvfs: verify that the built-in FSMonitor is disabled

  • 80: bdb2d72 = 89: 32f6ed5 wt-status: add trace2 data for sparse-checkout percentage

  • 81: 05a3899 = 90: 9bfac18 status: add status serialization mechanism

  • 82: 0004187 = 91: 193e7a2 Teach ahead-behind and serialized status to play nicely together

  • 83: eb99c1d = 92: 3ab1d75 status: serialize to path

  • 84: d1826ec = 93: 9be55c9 status: reject deserialize in V2 and conflicts

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

  • 86: 35c8e9d = 95: af8635a status: deserialization wait

  • 87: 71177dd = 96: 787969c status: deserialize with -uno does not print correct hint

  • 88: ffcf83b = 97: f29d65e fsmonitor: check CE_FSMONITOR_VALID in ce_uptodate

  • 89: 18e72af = 98: a916773 fsmonitor: add script for debugging and update script for tests

  • 90: de2e7db = 99: b9e929c status: disable deserialize when verbose output requested.

  • 91: 569e9a2 = 100: 7503d99 t7524: add test for verbose status deserialzation

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

  • 94: bb605dd = 102: 115a64e gvfs:trace2:data: add trace2 tracing around read_object_process

  • 96: 603a821 = 103: ec1b027 gvfs:trace2:data: status deserialization information

  • 98: 8f7c018 = 104: 6c3dfbd gvfs:trace2:data: status serialization

  • 100: c57a0fa = 105: b5d3600 gvfs:trace2:data: add vfs stats

  • 102: 0328598 = 106: 9ae932b trace2: refactor setting process starting time

  • 104: d877e37 = 107: 3f1d7c1 trace2:gvfs:experiment: report_tracking

  • 93: 8819c18 = 108: 8718e26 git.c: add VFS enabled cmd blocking

  • 105: 07bd962 = 109: f0e4207 trace2:gvfs:experiment: read_cache: annotate thread usage in read-cache

  • 95: 465d16d = 110: be11956 git.c: permit repack cmd in Scalar repos

  • 106: b80dc76 ! 111: dc929de trace2:gvfs:experiment: read-cache: time read/write of cache-tree extension

    @@ read-cache.c: static int read_index_extension(struct index_state *istate,
      	switch (CACHE_EXT(ext)) {
      	case CACHE_EXT_TREE:
     +		trace2_region_enter("index", "read/extension/cache_tree", NULL);
    - 		istate->cache_tree = cache_tree_read(data, sz);
    + 		istate->cache_tree = cache_tree_read(istate->repo, data, sz);
     +		trace2_data_intmax("index", NULL, "read/extension/cache_tree/bytes", (intmax_t)sz);
     +		trace2_region_leave("index", "read/extension/cache_tree", NULL);
      		break;
    @@ read-cache.c: static int do_write_index(struct index_state *istate, struct tempf
      		strbuf_reset(&sb);
      
     +		trace2_region_enter("index", "write/extension/cache_tree", NULL);
    - 		cache_tree_write(&sb, istate->cache_tree);
    + 		cache_tree_write(istate->repo, &sb, istate->cache_tree);
      		err = write_index_ext_header(f, eoie_c, CACHE_EXT_TREE, sb.len) < 0;
      		hashwrite(f, sb.buf, sb.len);
     +		trace2_data_intmax("index", NULL, "write/extension/cache_tree/bytes", (intmax_t)sb.len);
  • 97: 2960ca8 = 112: 491ddfa git.c: permit fsck cmd in Scalar repos

  • 107: d01c480 = 113: b407c07 trace2:gvfs:experiment: add region to apply_virtualfilesystem()

  • 99: 54c0591 = 114: 76b2053 git.c: permit prune cmd in Scalar repos

  • 108: 4637647 = 115: 6dfe362 trace2:gvfs:experiment: add region around unpack_trees()

  • 101: 1805df9 = 116: af6ff28 worktree: remove special case GVFS cmd blocking

  • 109: ad44619 ! 117: 7554357 trace2:gvfs:experiment: add region to cache_tree_fully_valid()

    @@ cache-tree.c: static void discard_unused_subtrees(struct cache_tree *it)
      	}
      }
      
    --int cache_tree_fully_valid(struct cache_tree *it)
    -+static int cache_tree_fully_valid_1(struct cache_tree *it)
    +-static int cache_tree_fully_valid_recursive(struct object_database *odb,
    +-					    struct cache_tree *it)
    ++static int cache_tree_fully_valid_recursive_1(struct object_database *odb,
    ++					      struct cache_tree *it)
      {
      	int i;
      	if (!it)
    -@@ cache-tree.c: int cache_tree_fully_valid(struct cache_tree *it)
    +@@ cache-tree.c: static int cache_tree_fully_valid_recursive(struct object_database *odb,
      			    ODB_HAS_OBJECT_RECHECK_PACKED | ODB_HAS_OBJECT_FETCH_PROMISOR))
      		return 0;
      	for (i = 0; i < it->subtree_nr; i++) {
    --		if (!cache_tree_fully_valid(it->down[i]->cache_tree))
    -+		if (!cache_tree_fully_valid_1(it->down[i]->cache_tree))
    +-		if (!cache_tree_fully_valid_recursive(odb, it->down[i]->cache_tree))
    ++		if (!cache_tree_fully_valid_recursive_1(odb, it->down[i]->cache_tree))
      			return 0;
      	}
      	return 1;
    -@@ cache-tree.c: static int must_check_existence(const struct cache_entry *ce)
    - 	return !(repo_has_promisor_remote(the_repository) && ce_skip_worktree(ce));
      }
      
    -+int cache_tree_fully_valid(struct cache_tree *it)
    ++static int cache_tree_fully_valid_recursive(struct object_database *odb,
    ++					    struct cache_tree *it)
     +{
     +	int result;
     +
     +	trace2_region_enter("cache_tree", "fully_valid", NULL);
    -+	result = cache_tree_fully_valid_1(it);
    ++	result = cache_tree_fully_valid_recursive_1(odb, it);
     +	trace2_region_leave("cache_tree", "fully_valid", NULL);
     +
     +	return result;
     +}
     +
    - static int update_one(struct cache_tree *it,
    - 		      struct cache_entry **cache,
    - 		      int entries,
    + int cache_tree_fully_valid(struct index_state *istate)
    + {
    + 	return cache_tree_fully_valid_recursive(istate->repo->objects,
  • 103: 9c8e4f5 = 118: b51cffb builtin/repack.c: emit warning when shared cache is present

  • 110: afce0be = 119: 26176b8 trace2:gvfs:experiment: add unpack_entry() counter to unpack_trees() and report_tracking()

  • 111: 4bd0068 = 120: f09b67d trace2:gvfs:experiment: increase default event depth for unpack-tree data

  • 112: bc48a14 = 121: 65f6c35 trace2:gvfs:experiment: add data for check_updates() in unpack_trees()

  • 113: e062a65 = 122: 11ffcc8 Trace2:gvfs:experiment: capture more 'tracking' details

  • 114: 776be05 = 123: 3fa557b credential: set trace2_child_class for credential manager children

  • 115: e9d624a = 124: bc332b6 sub-process: do not borrow cmd pointer from caller

  • 116: 75e2cab = 125: 09086b7 sub-process: add subprocess_start_argv()

  • 117: 352e3e6 = 126: fa9f21e sha1-file: add function to update existing loose object cache

  • 118: 1c21c53 = 127: 502918c index-pack: avoid immediate object fetch while parsing packfile

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

  • 129: de7a132 = 129: 2db620a sha1-file: create shared-cache directory if it doesn't exist

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

  • 130: 4aeefd4 = 131: 51f1386 gvfs-helper: better handling of network errors

  • 131: 16bf382 = 132: 7f4a505 gvfs-helper-client: properly update loose cache with fetched OID

  • 132: fb6b166 = 133: aea7e33 gvfs-helper: V2 robust retry and throttling

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

  • 134: 57a5026 = 135: ca5a532 gvfs-helper: dramatically reduce progress noise

  • 135: 8feadb0 = 136: 669cda6 gvfs-helper: handle pack-file after single POST request

  • 136: b82e5fd ! 137: 57d89ba test-gvfs-prococol, t5799: tests for gvfs-helper

    @@ contrib/buildsystems/CMakeLists.txt: set(wrapper_scripts
     
      ## gvfs-helper.c ##
     @@
    - #include "abspath.h"
      #include "progress.h"
      #include "trace2.h"
    + #include "gvfs.h"
     +#include "versioncmp.h"
      
      static const char * const main_usage[] = {
  • 137: 7393b9b = 138: d0bbcdd gvfs-helper: move result-list construction into install functions

  • 138: fa05036 = 139: b6b3d0f t5799: add support for POST to return either a loose object or packfile

  • 139: f299bd2 = 140: 085879c t5799: cleanup wc-l and grep-c lines

  • 140: bdf8316 = 141: 1761118 gvfs-helper: verify loose objects after write

  • 141: a0935f0 = 142: 9e4d6d2 t7599: create corrupt blob test

  • 142: 55e7432 ! 143: a366684 gvfs-helper: add prefetch support

    @@ gvfs-helper.c
      //            [2] Documentation/technical/long-running-process-protocol.txt
      //            [3] See GIT_TRACE_PACKET
     @@
    - #include "abspath.h"
      #include "progress.h"
      #include "trace2.h"
    + #include "gvfs.h"
     +#include "wrapper.h"
     +#include "packfile.h"
     +#include "date.h"
  • 143: 39ffced = 144: 9081419 gvfs-helper: add prefetch .keep file for last packfile

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

  • 145: ea44858 = 146: c49e061 gvfs-helper: move content-type warning for prefetch packs

  • 146: 799b046 = 147: da218cf fetch: use gvfs-helper prefetch under config

  • 147: 8bbc3ae = 148: 5a0c9ce gvfs-helper: better support for concurrent packfile fetches

  • 148: cd13c40 = 149: d35d1ad remote-curl: do not call fetch-pack when using gvfs-helper

  • 149: cbac56f = 150: 8a3a478 fetch: reprepare packs before checking connectivity

  • 150: f66ba48 = 151: e6abb7b gvfs-helper: retry when creating temp files

  • 151: a81292e = 152: 9074f57 sparse: avoid warnings about known cURL issues in gvfs-helper.c

  • 163: c6476e4 = 153: ae1b721 gvfs-helper: add --max-retries to prefetch verb

  • 166: 146e046 = 154: 550d785 t5799: add tests to detect corrupt pack/idx files in prefetch

  • 169: 5b86976 = 155: 824accb gvfs-helper: ignore .idx files in prefetch multi-part responses

  • 172: 8199341 = 156: 1c06ba8 t5799: explicitly test gvfs-helper --fallback and --no-fallback

  • 175: 0ac5663 = 157: 8f1f114 gvfs-helper: don't fallback with new config

  • 177: 28136c3 = 158: cf79810 test-gvfs-protocol: add cache_http_503 to mayhem

  • 152: 0e9b50b = 159: 15955cf maintenance: care about gvfs.sharedCache config

  • 179: 5443476 = 160: b5cab59 t5799: add unit tests for new gvfs.fallback config setting

  • 153: bdd9ee9 = 161: cb7ad0b unpack-trees:virtualfilesystem: Improve efficiency of clear_ce_flags

  • 160: 0aa9ecc = 162: db7bf8e update-microsoft-git: create barebones builtin

  • 162: e9f57fb = 163: 3d22821 update-microsoft-git: Windows implementation

  • 165: da68df6 = 164: 236dd62 update-microsoft-git: use brew on macOS

  • 168: 6064249 = 165: 87eff26 .github: reinstate ISSUE_TEMPLATE.md for microsoft/git

  • 171: 365ecfd = 166: 0ca8687 .github: update PULL_REQUEST_TEMPLATE.md

  • 154: 7cc0768 = 167: e083895 Disable the monitor-components workflow in msft-git

  • 174: 1fa3d0b = 168: 3d8b726 Adjust README.md for microsoft/git

  • 155: 79a7d58 = 169: 0c2b041 .github: enable windows builds on microsoft fork

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

  • 157: b76e04a = 171: 1cb5171 release: create initial Windows installer build workflow

  • 181: c57d4f9 = 172: 9959362 scalar: implement a minimal JSON parser

  • 158: 97ba474 = 173: 3b76db4 help: special-case HOST_CPU universal

  • 182: a37814f = 174: 2afa625 scalar clone: support GVFS-enabled remote repositories

  • 159: dfb31a0 = 175: 0f618ed release: add Mac OSX installer build

  • 183: 0276544 = 176: bc5eb4b test-gvfs-protocol: also serve smart protocol

  • 161: 857c903 = 177: d52f6fb release: build unsigned Ubuntu .deb package

  • 184: 7b4bab3 = 178: 284e0a0 gvfs-helper: add the endpoint command

  • 164: 3506782 = 179: 3abdd32 release: add signing step for .deb package

  • 185: e383855 = 180: 1f84a71 dir_inside_of(): handle directory separators correctly

  • 167: 1a30429 = 181: a4ca71e release: create draft GitHub release with packages & installers

  • 186: fd05203 = 182: e629027 scalar: disable authentication in unattended mode

  • 170: 48fd064 = 183: dd44bd0 build-git-installers: publish gpg public key

  • 187: 016458c = 184: 6a60f66 abspath: make strip_last_path_component() global

  • 173: bd980c7 = 185: ad19277 release: continue pestering until user upgrades

  • 188: 2241451 = 186: 59077f5 scalar: do initialize gvfs.sharedCache

  • 176: e34165e = 187: 6721b29 dist: archive HEAD instead of HEAD^{tree}

  • 189: 5b87ef2 = 188: 9531cdf scalar diagnose: include shared cache info

  • 178: 2e92df1 = 189: b280761 release: include GIT_BUILT_FROM_COMMIT in MacOS build

  • 190: 888593b = 190: 04149c4 scalar: only try GVFS protocol on https:// URLs

  • 180: 85154d9 = 191: fa4f8aa release: remove the obsolete GitHub installer workflow

  • 192: 1673edc = 192: ac5e537 add/rm: allow adding sparse entries when virtual

  • 194: 6fb81e9 = 193: 89e87c5 sparse-checkout: add config to disable deleting dirs

  • 196: b30ac75 = 194: ecac8e8 diff: ignore sparse paths in diffstat

  • 191: b61c6b5 = 195: e4e0016 scalar: verify that we can use a GVFS-enabled repository

  • 198: e6d5e92 = 196: 3488094 repo-settings: enable sparse index by default

  • 193: ef2763e = 197: 10ebb67 scalar: add the cache-server command

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

  • 197: 04a9e88 = 199: 70e8e5d scalar: adjust documentation to the microsoft/git fork

  • 202: 94094dd = 200: bae5811 TO-CHECK: t1092: use quiet mode for rebase tests

  • 199: 4dbdb32 = 201: df33d6d scalar: enable untracked cache unconditionally

  • 204: 7061a7f = 202: 75d5414 reset: fix mixed reset when using virtual filesystem

  • 200: f75c7d8 = 203: dbef07a scalar: parse clone --no-fetch-commits-and-trees for backwards compatibility

  • 206: 1dfacca = 204: 4e56187 diff(sparse-index): verify with partially-sparse

  • 201: a9dc475 = 205: e53877a scalar: make GVFS Protocol a forced choice

  • 208: 19853e6 = 206: 32e5af4 stash: expand testing for git stash -u

  • 203: eb6abab = 207: fab48c9 scalar: work around GVFS Protocol HTTP/2 failures

  • 210: eccb43c = 208: f963cdc sparse-index: add ensure_full_index_with_reason()

  • 205: 8e69605 = 209: f70640d gvfs-helper-client: clean up server process(es)

  • 212: 0439844 = 210: cedaeec treewide: add reasons for expanding index

  • 207: bfdf76c = 211: 42890de scalar diagnose: accommodate Scalar's Functional Tests

  • 213: ae5c4a0 = 212: 4a598f6 treewide: custom reasons for expanding index

  • 209: 24ea019 = 213: 555d92e ci: run Scalar's Functional Tests

  • 214: 6157538 = 214: 7a1ee60 sparse-index: add macro for unaudited expansions

  • 211: 600c1aa = 215: e79d611 scalar: upgrade to newest FSMonitor config setting

  • 215: 3dd67ab = 216: f13ff22 Docs: update sparse index plan with logging

  • 216: 05b87ce = 217: 118b6bb sparse-index: log failure to clear skip-worktree

  • 217: c269a09 = 218: 713abdb stash: use -f in checkout-index child process

  • 218: e92a8e5 = 219: ffa770d sparse-index: do not copy hashtables during expansion

  • 219: aa73a14 = 220: b74aa97 TO-UPSTREAM: sub-process: avoid leaking cmd

  • 220: 4ceed76 = 221: bf9f191 remote-curl: release filter options before re-setting them

  • 221: 44ff449 = 222: 84b8512 transport: release object filter options

  • 222: f9c3c53 = 223: 9acea34 push: don't reuse deltas with path walk

  • 223: bcc1ac7 = 224: 5d6b49f maintenance: add cache-local-objects maintenance task

  • 224: 7a0c0e5 = 225: 6dab639 scalar.c: add cache-local-objects task

  • 225: ef56408 = 226: 0cc3de9 hooks: add custom post-command hook config

  • 226: b8de263 = 227: 54006fe TO-UPSTREAM: Docs: fix asciidoc failures from short delimiters

  • 227: 1df86bc = 228: 699c357 hooks: make hook logic memory-leak free

  • 228: 5a24d2a = 229: 7eba3af t0401: test post-command for alias, version, typo

  • 229: cb7bbfc = 230: 8558aa6 hooks: better handle config without gitdir

  • 230: 5fc95bf = 231: c77fe05 scalar: add run_git_argv

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

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

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

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

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

  • 236: 890f643 = 237: c8341af gvfs-helper: override cache server for prefetch

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

  • 238: 89ecacd = 239: 2296011 gvfs-helper: override cache server for post

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

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

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

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

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

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

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

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

  • 248: dfc9ab9 ! 248: fce704b gvfs-helper: create shared object cache if missing

    @@ gvfs-helper.c: static int option_parse_shared_cache_directory(const struct optio
     +						gvfs_shared_cache_pathname.buf);
     +		mkdir(gvfs_shared_cache_pathname.buf, 0777);
     +
    - 		odb_add_to_alternates_memory(the_repository->objects, buf_arg.buf);
    + 		add_gvfs_shared_cache_to_alternates(the_repository->objects, buf_arg.buf);
      
      		strbuf_release(&buf_arg);
      		return 0;
    @@ gvfs-helper.c: static int option_parse_shared_cache_directory(const struct optio
     +						gvfs_shared_cache_pathname.buf);
     +		mkdir(gvfs_shared_cache_pathname.buf, 0777);
     +
    - 		odb_add_to_alternates_memory(the_repository->objects, buf_arg.buf);
    + 		add_gvfs_shared_cache_to_alternates(the_repository->objects, buf_arg.buf);
      
      		/*
     
  • 247: c9dc6e0 ! 249: 1f725d7 gvfs-helper: send X-Session-Id headers

    @@ Commit message
     
      ## gvfs-helper.c ##
     @@
    - #include "abspath.h"
      #include "progress.h"
      #include "trace2.h"
    + #include "gvfs.h"
     +#include "trace2/tr2_sid.h"
      #include "wrapper.h"
      #include "packfile.h"
  • 249: cb1bad8 = 250: 204ccf2 gvfs: add gvfs.sessionKey config

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

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

  • 252: 4ec183e = 253: ef7f7fd ci: add new VFS for Git functional tests workflow

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

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

  • 255: ca2cb70 = 256: 50951a5 gvfs-helper: separate packfile extraction from indexing

  • 256: 562d21c = 257: f2e175d blame: add blame.renames, blame.renameThreshold, blame.renameLimit

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

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

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

  • 260: 4a4c90b = 261: eb515d7 azure-pipelines: allow overriding Git version

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

  • 262: 0cb444a = 263: bac85b6 azure-pipelines: add signed macOS ARM64 releases

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

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

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

  • 266: 7215421 = 267: e26f975 release: suppress unfixable binskim findings

  • 267: a75c9be = 268: 1ac3713 binskim: add baseline

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

  • 269: 6367af0 (upstreamed as: ce6f9ff) < -: ----------- rust: pick a GCC-compatible Cargo target under MSYS2/MinGW

  • 270: 24cb175 = 270: 428f04e ci(vfs): install the GCC-compatible Rust target before building

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

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

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

  • 274: 984500a = 274: 9b99ba8 trace2: tolerate failed timestamp formatting

  • 275: 9166bf9 = 275: 846d5de reset --mixed: clear skip-worktree for all changed entries in VFS mode

  • 276: 661a3ec = 276: 36faa37 send-pack: add gvfs.negativeRefCheck to skip missing negatives

  • 277: 1db3949 ! 277: 74d7f80 odb: scan all sources' packfiles before loose objects

    @@ Commit message
         Signed-off-by: Tyrie Vella <tyrielv@gmail.com>
     
      ## odb.c ##
    -@@ odb.c: static int register_all_submodule_sources(struct object_database *odb)
    - 	return ret;
    +@@ odb.c: void disable_obj_read_lock(void)
    + 	pthread_mutex_destroy(&obj_read_mutex);
      }
      
     +static enum odb_read_status read_object_info_from_sources(
  • 278: 077213e = 278: 6fd9369 scalar: add --[no-]prefetch option

  • 279: a18dd2a = 279: a8aab29 scalar: request for commit via POST

  • 280: 478fbc7 = 280: 919a530 odb: warn when ignoring unusable alternates

  • 281: a67c7c2 = 281: 7bf7e90 ci: avoid vcpkg telemetry contention during MSBuild

  • 282: 9e91310 = 282: a3273f7 rust: honor the active MinGW prefix when invoking Cargo

  • 283: b91c1f8 = 283: 92bfd44 cmake: default the Windows runtime prefix to UCRT64

  • 284: 65c9292 = 284: 5ae7fad gvfs-helper: add gvfs.postThreads config option

  • 285: 142551d = 285: 2b87ce6 http: factor reusable curl handle preparation

  • 286: 98a8cdf = 286: dc15f86 gvfs-helper: parallelize POST object requests

  • 287: 79c7b55 = 287: e86ce06 gvfs-helper: preserve POST failure handling in parallel mode

  • 288: 551e1d7 = 288: bc00162 t5798: test parallel POST object requests

  • 289: f332ea4 = 289: eefe24c t5798: test parallel POST failure handling

(clean/vfs-2.56.0-rc0 is a heavily auto-squashed, tree-same version of #984's PR branch)

The fsmonitor script that can be used for running all the git tests
using watchman was causing some of the tests to fail because it wrote
to stderr and created some files for debugging purposes.

Add a new debug script to use with debugging and modify the other script
to remove the code that would cause tests to fail.

Signed-off-by: Kevin Willford <Kevin.Willford@microsoft.com>
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
The following commands and options are not currently supported when working
in a GVFS repo.  Add code to detect and block these commands from executing.

1) fsck
2) gc
4) prune
5) repack
6) submodule
8) update-index --split-index
9) update-index --index-version (other than 4)
10) update-index --[no-]skip-worktree
11) worktree

Signed-off-by: Ben Peart <benpeart@microsoft.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Loosen the blocking of the `prune` command from all "GVFS repos" (those
that have `core.gvfs` set) to only those that actually use the virtual
file system (VFS for Git only). This allows for `prune` to be used in
Scalar clones.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
When our patches to support that hook were upstreamed, the hook's name
was eliciting some reviewer suggestions, and it was renamed to
`post-index-change`. These patches (with the new name) made it into
v2.22.0.

However, VFSforGit users may very well have checkouts with that hook
installed under the original name.

To support this, let's just introduce a hack where we look a bit more
closely when we just failed to find the `post-index-change` hook, and
allow any `post-indexchanged` hook to run instead (if it exists).
Disable deserialization when verbose output requested.

Verbose mode causes Git to print diffs for modified files.
This requires the index to be loaded to have the currently
staged OID values.  Without loading the index, verbose output
make it look like everything was deleted.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
In earlier versions of `microsoft/git`, we found a user who had set
`core.gvfs = false` in their global config. This should not have been
necessary, but it also should not have caused a problem. However, it
did.

The reason was that `gvfs_load_config_value()` was called from
`config.c` when reading config key/value pairs from all the config
files. The local config should override the global config, and this is
done by `config.c` reading the global config first then reading the
local config. However, our logic only allowed writing the `core_gvfs`
variable once.

In v2.51.0, we had to adapt to upstream changes that changed way the
`core.gvfs` config value is read, and the special handling is no longer
necessary, yet we still want the test case that ensures that this bug
does not experience a regression.

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>
Replace the special casing of the `worktree` command being blocked on
VFS-enabled repos with the new `BLOCK_ON_VFS_ENABLED` flag.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
When using a virtual file system layer, the FSMonitor does not make
sense.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Verify that `git status --deserialize=x -v` does not crash and
generates the same output as a normal (scanning) status command.

These issues are described in the previous 2 commits.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Emit a warning message when the `gvfs.sharedCache` option is set that
the `repack` command will not perform repacking on the shared cache.

In the future we can teach `repack` to operate on the shared cache, at
which point we can drop this commit.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
When sparse-checkout is enabled, add the sparse-checkout percentage to
the Trace2 data stream.  This number was already computed and printed
on the console in the "You are in a sparse checkout..." message.  It
would be helpful to log it too for performance monitoring.

Signed-off-by: Jeff Hostetler <jeffhostetler@github.com>
Teach Git to not throw a fatal error when an explicitly-specified
status-cache file (`git status --deserialize=<foo>`) could not be
found or opened for reading and silently fallback to a traditional
scan.

This matches the behavior when the status-cache file is implicitly
given via a config setting.

Note: the current version causes a test to start failing. Mark this as
an expected result for now.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Teach subprocess_start() to use a copy of the passed `cmd` string
rather than borrowing the buffer from the caller.

Some callers of subprocess_start() pass the value returned from
find_hook() which points to a static buffer and therefore is only
good until the next call to find_hook().  This could cause problems
for the long-running background processes managed by sub-process.c
where later calls to subprocess_find_entry() to get an existing
process will fail.  This could cause more than 1 long-running
process to be created.

TODO Need to confirm, but if only read_object_hook() uses
TODO subprocess_start() in this manner, we could drop this
TODO commit when we drop support for read_object_hook().

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Add function to start a subprocess with an argv.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Create a function to add a new object to the loose object cache
after the existing odb/xx/ directory was scanned.

This will be used in a later commit to keep the loose object
cache fresh after dynamically fetching an individual object
and without requiring the odb/xx/ directory to be rescanned.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
…and report_tracking()

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Prevent packfile parsing from accidentally dynamically fetching
each individual object found in the packfile.

When index-pack parses the input packfile, it does a lookup in the
ODB to test for conflicts/collisions.  This can accidentally cause
the object to be individually fetched when gvfs-helper (or
read-object-hook or partial-clone) is enabled.

The call site was migrated to odb_has_object() as part of the upstream
refactoring, but odb_has_object(odb, oid, HAS_OBJECT_FETCH_PROMISOR)
sets only OBJECT_INFO_QUICK without OBJECT_INFO_SKIP_FETCH_OBJECT, which
means it WILL trigger remote fetches via gvfs-helper. But we want to
prevent index-pack from individually fetching every object it encounters
during the collision check.

Passing 0 instead gives us both OBJECT_INFO_QUICK and
OBJECT_INFO_SKIP_FETCH_OBJECT, which is the correct equivalent of the
original OBJECT_INFO_FOR_PREFETCH behavior.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Create gvfs-helper.  This is a helper tool to use the GVFS Protocol
REST API to fetch objects and configuration data from a GVFS cache-server
or Git server.  This tool uses libcurl to send object requests to either
server.  This tool creates loose objects and/or packfiles.

Create gvfs-helper-client.  This code resides within git proper and
uses the sub-process API to manage gvfs-helper as a long-running background
process.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Derrick Stolee <dstolee@microsoft.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>
The config variable `gvfs.sharedCache` contains the pathname to an alternate
<odb> that will be used by `gvfs-helper` to store dynamically-fetched missing
objects.  If this directory does not exist on disk, `prepare_alt_odb()` omits
this directory from the in-memory list of alternates.  This causes `git`
commands (and `gvfs-helper` in particular) to fall-back to `.git/objects` for
storage of these objects.  This disables the shared-cache and leads to poorer
performance.

Teach `alt_obj_usable()` and `prepare_alt_odb()`, match up the directory
named in `gvfs.sharedCache` with an entry in `.git/objects/info/alternates`
and force-create the `<odb>` root directory (and the associated `<odb>/pack`
directory) if necessary.

If the value of `gvfs.sharedCache` refers to a directory that is NOT listed
as an alternate, create an in-memory alternate entry in the odb-list.  (This
is similar to how GIT_ALTERNATE_OBJECT_DIRECTORIES works.)

This work happens the first time that `prepare_alt_odb()` is called.

Furthermore, teach the `--shared-cache=<odb>` command line option in
`gvfs-helper` (which is runs after the first call to `prepare_alt_odb()`)
to override the inherited shared-cache (and again, create the ODB directory
if necessary).

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.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>
Upstream Git is _very_ keen on not allowing in-memory addition of
alternates, see f0eb23a (odb: remove the ability to link sources
ad-hoc, 2026-09-11). However, we really need this functionality here.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Add trace2 message for CURL and HTTP errors.

Fix typo reporting network error code back to gvfs-helper-client.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Fix parsing of the "loose <odb>" response from `gvfs-helper` and
use the actually parsed OID when updating the loose oid cache.

Previously, an uninitialized "struct oid" was used to update
the cache.  This did not cause any corruption, but could cause
extra fetches for objects visited multiple times.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Promoting a microsoft/git release into the microsoft/homebrew-git tap
used to be handled by `release-homebrew.yml`, which authenticated to
Azure via OIDC, pulled a GitHub PAT from an Azure Key Vault, and
pushed to the tap. That plumbing existed because the prior internal
guidance mandated GitHub-Actions-native federated identity to Azure
and deprecated the Azure Pipelines automation this workflow had
originally replaced.

That guidance has now reversed: federated identity from GitHub
Actions to Azure has been turned off. Rather than migrate the
automation a third time (and rebuild the full plumbing needed to
fetch a PAT via Azure Pipelines with workload identity into Key
Vault under the new rules), replace the workflow with a script the
operator runs by hand while promoting a pre-release to a full
release. The operator's own `gh auth login` session already has push
access to microsoft/homebrew-git, so the entire OIDC-to-Key-Vault
chain disappears.

The script reproduces the behaviour of the previously-used
`mjcheetham/update-homebrew@v1.5.1` action invoked with `type:
cask, alwaysUsePullRequest: false`: it locates the single
`git-*.pkg` asset for the tag, rewrites `version` and `sha256` in
the cask, commits, and pushes to the tap's default branch. The
`sha256` is taken from the asset's API-reported `digest` field
rather than recomputed locally, because microsoft/homebrew-git#102
documented cases where GitHub occasionally served the "unicorn" 500
page with a 200 status for an asset download, which then poisons
any locally computed hash.

This is the first of three such scripts (homebrew, vfsforgit,
winget) that will supersede the corresponding workflows; a
follow-up commit will delete those workflows and the local
`.github/actions/akv-secret/` composite action once all three
replacements are in place.

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>
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>
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>
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.
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.
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.
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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 3906f0e into vfs-2.56.0-rc1 Sep 23, 2026
167 checks passed
@dscho
Johannes Schindelin (dscho) deleted the tentative/vfs-2.56.0-rc1 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.