Skip to content

Conversation

@dscho
Copy link
Member

@dscho dscho commented Nov 7, 2025

The usual thing. See git-for-windows#5937.

mjcheetham and others added 30 commits November 6, 2025 23:34
Verify that the core.hooksPath configuration is repsected by the
pre-command hook. Original regression test was written by
Alejandro Pauly.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Signed-off-by: Alejandro Pauly <alpauly@microsoft.com>
When using the sparse-checkout feature, the file might not be on disk
because the skip-worktree bit is on. This used to be a bug in the
(hence deleted) `recursive` strategy. Let's ensure that this bug does
not resurface.

Signed-off-by: Kevin Willford <kewillf@microsoft.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The 'git worktree' command was marked as BLOCK_ON_GVFS_REPO because it
does not interact well with the virtual filesystem of VFS for Git. When
a Scalar clone uses the GVFS protocol, it enables the
GVFS_BLOCK_COMMANDS flag, since commands like 'git gc' do not work well
with the GVFS protocol.

However, 'git worktree' works just fine with the GVFS protocol since it
isn't doing anything special. It copies the sparse-checkout from the
current worktree, so it does not have performance issues.

This is a highly requested option.

The solution is to stop using the BLOCK_ON_GVFS_REPO option and instead
add a special-case check in cmd_worktree() specifically for a particular
bit of the 'core_gvfs' global variable (loaded by very early config
reading) that corresponds to the virtual filesystem. The bit that most
closely resembled this behavior was non-obviously named, but does
provide a signal that we are in a Scalar clone and not a VFS for Git
clone. The error message is copied from git.c, so it will have the same
output as before if a user runs this in a VFS for Git clone.

Signed-off-by: Derrick Stolee <derrickstolee@github.com>
When using the sparse-checkout feature git should not write to the working
directory for files with the skip-worktree bit on.  With the skip-worktree
bit on the file may or may not be in the working directory and if it is
not we don't want or need to create it by calling checkout_entry.

There are two callers of checkout_target.  Both of which check that the
file does not exist before calling checkout_target.  load_current which
make a call to lstat right before calling checkout_target and
check_preimage which will only run checkout_taret it stat_ret is less than
zero.  It sets stat_ret to zero and only if !stat->cached will it lstat
the file and set stat_ret to something other than zero.

This patch checks if skip-worktree bit is on in checkout_target and just
returns so that the entry doesn't not end up in the working directory.
This is so that apply will not create a file in the working directory,
then update the index but not keep the working directory up to date with
the changes that happened in the index.

Signed-off-by: Kevin Willford <kewillf@microsoft.com>
Signed-off-by: Kevin Willford <kewillf@microsoft.com>
Add the ability to block built-in commands based on if the `core.gvfs`
setting has the `GVFS_USE_VIRTUAL_FILESYSTEM` bit set. This allows us
to selectively block commands that use the GVFS protocol, but don't use
VFS for Git (for example repos cloned via `scalar clone` against Azure
DevOps).

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
While performing a fetch with a virtual file system we know that there
will be missing objects and we don't want to download them just because
of the reachability of the commits.  We also don't want to download a
pack file with commits, trees, and blobs since these will be downloaded
on demand.

This flag will skip the first connectivity check and by returning zero
will skip the upload pack. It will also skip the second connectivity
check but continue to update the branches to the latest commit ids.

Signed-off-by: Kevin Willford <kewillf@microsoft.com>
As of 9e59b38 (object-file: emit corruption errors when detected,
2022-12-14), Git will loudly complain about corrupt objects.

That is fine, as long as the idea isn't to re-download locally-corrupted
objects. But that's exactly what we want to do in VFS for Git via the
`read-object` hook, as per the `GitCorruptObjectTests` code
added in microsoft/VFSForGit@2db0c030eb25 (New
features: [...] -  GVFS can now recover from corrupted git object files
[...] , 2018-02-16).

So let's support precisely that, and add a regression test that ensures
that re-downloading corrupt objects via the `read-object` hook works.

While at it, avoid the XOR operator to flip the bits, when we actually
want to make sure that they are turned off: Use the AND-NOT operator for
that purpose.

Helped-by: Matthew John Cheetham <mjcheetham@outlook.com>
Helped-by: Derrick Stolee <stolee@gmail.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Loosen the blocking of the `repack` 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 `repack` to be used in
Scalar clones.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
Ensure all filters and EOL conversions are blocked when running under
GVFS so that our projected file sizes will match the actual file size
when it is hydrated on the local machine.

Signed-off-by: Ben Peart <Ben.Peart@microsoft.com>
String formatting can be a performance issue when there are
hundreds of thousands of trees.

Change to stop using the strbuf_addf and just add the strings
or characters individually.

There are a limited number of modes so added a switch for the
known ones and a default case if something comes through that
are not a known one for git.

In one scenario regarding a huge worktree, this reduces the
time required for a `git checkout <branch>` from 44 seconds
to 38 seconds, i.e. it is a non-negligible performance
improvement.

Signed-off-by: Kevin Willford <kewillf@microsoft.com>
Loosen the blocking of the `fsck` 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 `fsck` to be used in
Scalar clones.

Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
The idea is to allow blob objects to be missing from the local repository,
and to load them lazily on demand.

After discussing this idea on the mailing list, we will rename the feature
to "lazy clone" and work more on this.

Signed-off-by: Ben Peart <Ben.Peart@microsoft.com>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
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>
On index load, clear/set the skip worktree bits based on the virtual
file system data. Use virtual file system data to update skip-worktree
bit in unpack-trees. Use virtual file system data to exclude files and
folders not explicitly requested.

Update 2022-04-05: disable the "present-despite-SKIP_WORKTREE" file removal
behavior when 'core.virtualfilesystem' is enabled.

Signed-off-by: Ben Peart <benpeart@microsoft.com>
Hydrate missing loose objects in check_and_freshen() when running
virtualized. Add test cases to verify read-object hook works when
running virtualized.

This hook is called in check_and_freshen() rather than
check_and_freshen_local() to make the hook work also with alternates.

Helped-by: Kevin Willford <kewillf@microsoft.com>
Signed-off-by: Ben Peart <Ben.Peart@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>
…x has been redirected

Fixes #13

Some git commands spawn helpers and redirect the index to a different
location.  These include "difftool -d" and the sequencer
(i.e. `git rebase -i`, `git cherry-pick` and `git revert`) and others.
In those instances we don't want to update their temporary index with
our virtualization data.

Helped-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Ben Peart <Ben.Peart@microsoft.com>
If we are going to write an object there is no use in calling
the read object hook to get an object from a potentially remote
source.  We would rather just write out the object and avoid the
potential round trip for an object that doesn't exist.

This change adds a flag to the check_and_freshen() and
freshen_loose_object() functions' signatures so that the hook
is bypassed when the functions are called before writing loose
objects. The check for a local object is still performed so we
don't overwrite something that has already been written to one
of the objects directories.

Based on a patch by Kevin Willford.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
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>
Add trace2 region around read_object_process to collect
time spent waiting for missing objects to be dynamically
fetched.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Add trace2 region and data events describing attempts to deserialize
status data using a status cache.

A category:status, label:deserialize region is pushed around the
deserialize code.

Deserialization results when reading from a file are:
    category:status, path   = <path>
    category:status, polled = <number_of_attempts>
    category:status, result = "ok" | "reject"

When reading from STDIN are:
    category:status, path   = "STDIN"
    category:status, result = "ok" | "reject"

Status will fallback and run a normal status scan when a "reject"
is reported (unless "--deserialize-wait=fail").

If "ok" is reported, status was able to use the status cache and
avoid scanning the workdir.

Additionally, a cmd_mode is emitted for each step: collection,
deserialization, and serialization.  For example, if deserialization
is attempted and fails and status falls back to actually computing
the status, a cmd_mode message containing "deserialize" is issued
and then a cmd_mode for "collect" is issued.

Also, if deserialization fails, a data message containing the
rejection reason is emitted.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Add trace information around status serialization.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Report virtual filesystem summary data.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Teach STATUS to optionally serialize the results of a
status computation to a file.

Teach STATUS to optionally read an existing serialization
file and simply print the results, rather than actually
scanning.

This is intended for immediate status results on extremely
large repos and assumes the use of a service/daemon to
maintain a fresh current status snapshot.

2021-10-30: packet_read() changed its prototype in ec9a37d (pkt-line.[ch]:
remove unused packet_read_line_buf(), 2021-10-14).

2021-10-30: sscanf() now does an extra check that "%d" goes into an "int"
and complains about "uint32_t". Replacing with "%u" fixes the compile-time
error.

2021-10-30: string_list_init() was removed by abf897b (string-list.[ch]:
remove string_list_init() compatibility function, 2021-09-28), so we need to
initialize manually.

Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com>
Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
dscho and others added 9 commits November 6, 2025 23:34
A few places where CodeQL thinks that variables might be uninitialized.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
…oes NUL-terminate correctly

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The code is a bit too hard to reason about for CodeQL to figure out
whether the `fill_commit_graph_info()`  function is at all called after
`write_commit_graph()` returns (and hence whether `topo_levels` goes out
of context before it is used again).

The Git project insists that this is correct (and does not want to make
the code more obviously correct), so let's silence CodeQL's complaints
in this instance.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
These patches implement some defensive programming to address complaints
some static analyzers might have.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Let's exclude GitWeb from being scanned; It is not distributed by us.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
CodeQL pointed out a couple of issues, which are addressed in this patch
series.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This patch series has been long in the making, ever since Johannes
Nicolai and myself spiked this in November/December 2020.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
The microsoft/git fork includes pre- and post-command hooks, with the
initial intention of using these for VFS for Git. In that environment,
these are important hooks to avoid concurrent issues when the
virtualization is incomplete.

However, in the Office monorepo the post-command hook is used in a
different way. A custom hook is used to update the sparse-checkout, if
necessary. To avoid this hook from being incredibly slow on every Git
command, this hook checks for the existence of a "sentinel file" that is
written by a custom post-index-change hook and no-ops if that file does
not exist.

However, even this "no-op" is 200ms due to the use of two scripts (one
simple script in .git/hooks/ does some environment checking and then
calls a script from the working directory which actually contains the
logic).

Add a new config option, 'postCommand.strategy', that will allow for
multiple possible strategies in the future. For now, the one we are
adding is 'post-index-change' which states that we should write a
sentinel file instead of running the 'post-index-change' hook and then
skip the 'post-command' hook if the proper sentinel file doesn't exist.
(If it does exist, then delete it and run the hook.)

--- 

This fork contains changes specific to monorepo scenarios. If you are an
external contributor, then please detail your reason for submitting to
this fork:

* [ ] This is an early version of work already under review upstream.
* [ ] This change only applies to interactions with Azure DevOps and the
      GVFS Protocol.
* [ ] This change only applies to the virtualization hook and VFS for
Git.
* [x] This change only applies to custom bits in the microsoft/git fork.
This patch series has been long in the making, ever since Johannes
Nicolai and myself spiked this in November/December 2020.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho dscho requested a review from mjcheetham November 7, 2025 09:00
@dscho dscho self-assigned this Nov 7, 2025
@dscho
Copy link
Member Author

dscho commented Nov 7, 2025

Range-diff relative to v2.52.0-rc0
  • 1: a13b3b6 = 1: 6081007 sparse-index.c: fix use of index hashes in expand_index

  • 3: ce22fc8 = 2: f529fee t: remove advice from some tests

  • 5: bc8fe5d = 3: 76341fc survey: calculate more stats on refs

  • 8: cc9d08f = 4: 69e1f09 survey: show some commits/trees/blobs histograms

  • 9: e7f1e6a = 5: 402671a survey: add vector of largest objects for various scaling dimensions

  • 10: 4db694f = 6: 3d75e37 survey: add pathname of blob or tree to large_item_vec

  • 11: 5430993 = 7: edd4dd9 survey: add commit-oid to large_item detail

  • 12: 2ff6aa1 = 8: 2d2440a survey: add commit name-rev lookup to each large_item

  • 41: 0e5310e = 9: fd8c53b survey: add --no-name-rev option

  • 42: b38a286 = 10: a69bb38 survey: started TODO list at bottom of source file

  • 2: b924ab9 = 11: 5e3d859 t5300: confirm failure of git index-pack when non-idx suffix requested

  • 4: 5e87d2d = 12: d1fec99 t1092: add test for untracked files and directories

  • 43: 8bc6410 = 13: c072698 survey: expanded TODO list at the bottom of the source file

  • 6: 29cdb90 = 14: 4805b22 index-pack: disable rev-index if index file has non .idx suffix

  • 44: 3ac4451 = 15: 0ffc991 survey: expanded TODO with more notes

  • 7: 06a9722 = 16: c3d4c2e trace2: prefetch value of GIT_TRACE2_DST_DEBUG at startup

  • 45: 45ebce6 = 17: a226163 reset --stdin: trim carriage return from the paths

  • 46: c0f7611 ! 18: 99fffed Identify microsoft/git via a distinct version suffix

    @@ Commit message
      ## GIT-VERSION-GEN ##
     @@
      
    - DEF_VER=v2.52.0-rc0
    + DEF_VER=v2.52.0-rc1
      
     +# Identify microsoft/git via a distinct version suffix
     +DEF_VER=$DEF_VER.vfs.0.0
  • 47: a94c4d4 = 19: a0fa0a3 gvfs: ensure that the version is based on a GVFS tag

  • 48: c88546c = 20: 0b76c77 gvfs: add a GVFS-specific header file

  • 49: a233cc2 = 21: 398f0a8 gvfs: add the core.gvfs config setting

  • 50: 96c16e4 = 22: eacf0f8 gvfs: add the feature to skip writing the index' SHA-1

  • 51: 821ea8e = 23: ee95d90 gvfs: add the feature that blobs may be missing

  • 52: 68d9b9f = 24: e44934e gvfs: prevent files to be deleted outside the sparse checkout

  • 53: 9bd1d2e = 25: 865ad69 gvfs: optionally skip reachability checks/upload pack during fetch

  • 54: e0b0666 = 26: 6debd02 gvfs: ensure all filters and EOL conversions are blocked

  • 55: 6d06207 = 27: f05ab93 gvfs: allow "virtualizing" objects

  • 56: 9e9710e = 28: 45bc37e Hydrate missing loose objects in check_and_freshen()

  • 57: 2381f6a = 29: 09e275b sha1_file: when writing objects, skip the read_object_hook

  • 65: ea13c03 ! 30: c58e290 gvfs: add global command pre and post hook procs

    @@ t/t0401-post-command-hook.sh (new)
     +'
     +
     +test_done
    +
    + ## t/t7502-commit-porcelain.sh ##
    +@@ t/t7502-commit-porcelain.sh: EOF
    + '
    + 
    + test_expect_success WITH_BREAKING_CHANGES 'core.commentChar=auto is rejected' '
    ++	cat >&2 <<-EOF &&
    ++	Trying to run any pre-command hook already triggers a failure when
    ++	running \`git config core.commentChar auto\`; Skipping this test.
    ++	EOF
    ++	return 0 &&
    + 	test_config core.commentChar auto &&
    + 	test_must_fail git rev-parse --git-dir 2>err &&
    + 	sed -n "s/^hint: *\$//p; s/^hint: //p; s/^fatal: //p" err >actual &&
  • 66: d35ee8d = 31: ac0ec4b t0400: verify that the hook is called correctly from a subdirectory

  • 67: 8a72bf7 = 32: 7b055ef t0400: verify core.hooksPath is respected by pre-command

  • 68: 91f0c82 = 33: 84a9f21 Pass PID of git process to hooks.

  • 69: b7a7125 = 34: 86b3ace sparse-checkout: make sure to update files with a modify/delete conflict

  • 70: a2c1d35 = 35: c93e9cc worktree: allow in Scalar repositories

  • 71: d206292 = 36: e457acc sparse-checkout: avoid writing entries with the skip-worktree bit

  • 72: e54a143 = 37: 4dfc57b Do not remove files outside the sparse-checkout

  • 73: bdd0477 = 38: 356b77b send-pack: do not check for sha1 file when GVFS_MISSING_OK set

  • 74: d04b499 = 39: 9ad7897 gvfs: allow corrupt objects to be re-downloaded

  • 75: 610bacb = 40: d69a3d4 cache-tree: remove use of strbuf_addf in update_one

  • 76: b88a9ce = 41: d4cfab6 gvfs: block unsupported commands when running in a GVFS repo

  • 77: 7c28999 = 42: 950df92 gvfs: allow overriding core.gvfs

  • 78: b43844d = 43: b4b05e8 BRANCHES.md: Add explanation of branches and using forks

  • 80: 4320650 = 44: 05ee0b9 git.c: add VFS enabled cmd blocking

  • 82: c335e49 = 45: 5c2f5ed git.c: permit repack cmd in Scalar repos

  • 84: fc23cca = 46: eff66c9 git.c: permit fsck cmd in Scalar repos

  • 86: 0f1c8fa = 47: 58dc4b5 git.c: permit prune cmd in Scalar repos

  • 79: 35c23ee = 48: b0f44ca Add virtual file system settings and hook proc

  • 88: 414949f = 49: eea9562 worktree: remove special case GVFS cmd blocking

  • 81: b4e1cd0 = 50: eda1d40 virtualfilesystem: don't run the virtual file system hook if the index has been redirected

  • 90: 22e962e = 51: e9ef0c2 builtin/repack.c: emit warning when shared cache is present

  • 83: 8b4db2c = 52: 467d1d4 virtualfilesystem: check if directory is included

  • 85: 879187e = 53: f9e2f23 backwards-compatibility: support the post-indexchanged hook

  • 87: 77cf91b = 54: 3f8b4f7 gvfs: verify that the built-in FSMonitor is disabled

  • 89: b2d8392 = 55: 5e6e299 wt-status: add trace2 data for sparse-checkout percentage

  • 91: d9fcb0b = 56: 65e5bc3 status: add status serialization mechanism

  • 92: 06cba35 = 57: 20e4772 Teach ahead-behind and serialized status to play nicely together

  • 93: 83841fa = 58: ce90612 status: serialize to path

  • 94: ea4b7cc = 59: 5707b36 status: reject deserialize in V2 and conflicts

  • 95: 9c63e85 = 60: 5fc191a serialize-status: serialize global and repo-local exclude file metadata

  • 96: cd3b841 = 61: d70c7c6 status: deserialization wait

  • 97: afef9e9 = 62: 690ab92 status: deserialize with -uno does not print correct hint

  • 98: f4f16b9 = 63: 3fe2870 fsmonitor: check CE_FSMONITOR_VALID in ce_uptodate

  • 99: 766798b = 64: 1593e99 fsmonitor: add script for debugging and update script for tests

  • 100: 21b4089 = 65: 94621f5 status: disable deserialize when verbose output requested.

  • 101: 77f39b5 = 66: 979f631 t7524: add test for verbose status deserialzation

  • 102: 8142cd7 = 67: bff4e05 deserialize-status: silently fallback if we cannot read cache file

  • 103: 10b3cec = 68: 095b0f6 gvfs:trace2:data: add trace2 tracing around read_object_process

  • 104: 69e430d = 69: 3b15177 gvfs:trace2:data: status deserialization information

  • 105: 3148bd6 = 70: 65079bb gvfs:trace2:data: status serialization

  • 106: b3c42cc = 71: debd329 gvfs:trace2:data: add vfs stats

  • 107: 47d83b9 = 72: a55a6a0 trace2: refactor setting process starting time

  • 108: 8553e35 = 73: 06f8b6e trace2:gvfs:experiment: clear_ce_flags_1

  • 109: cc29e0e = 74: bc9b062 trace2:gvfs:experiment: report_tracking

  • 110: ebd8cee = 75: c4c10f0 trace2:gvfs:experiment: read_cache: annotate thread usage in read-cache

  • 111: fb0c8e1 = 76: 2b00521 trace2:gvfs:experiment: read-cache: time read/write of cache-tree extension

  • 112: f8d7367 = 77: 31b4177 trace2:gvfs:experiment: add region to apply_virtualfilesystem()

  • 113: 648e50f = 78: 0030286 trace2:gvfs:experiment: add region around unpack_trees()

  • 114: 8d59be5 = 79: 4d778b3 trace2:gvfs:experiment: add region to cache_tree_fully_valid()

  • 115: d43bd29 = 80: bb2497f trace2:gvfs:experiment: add unpack_entry() counter to unpack_trees() and report_tracking()

  • 116: 130827e = 81: 48f19cc trace2:gvfs:experiment: increase default event depth for unpack-tree data

  • 117: 287fcdf = 82: b2d2a88 trace2:gvfs:experiment: add data for check_updates() in unpack_trees()

  • 118: db5daa8 = 83: 20aebf2 Trace2:gvfs:experiment: capture more 'tracking' details

  • 119: a33a33b = 84: 3c8c9ff credential: set trace2_child_class for credential manager children

  • 120: eee1de9 = 85: 8dbdc4a sub-process: do not borrow cmd pointer from caller

  • 121: 2722193 = 86: 78e57b3 sub-process: add subprocess_start_argv()

  • 122: c62971c = 87: 7c6fc31 sha1-file: add function to update existing loose object cache

  • 123: 6e7e322 = 88: 945117a packfile: add install_packed_git_and_mru()

  • 124: ffc80f3 = 89: 79853d0 index-pack: avoid immediate object fetch while parsing packfile

  • 125: 81938b8 = 90: 58a4bd9 gvfs-helper: create tool to fetch objects using the GVFS Protocol

  • 126: 79e494a = 91: 77c43a8 sha1-file: create shared-cache directory if it doesn't exist

  • 127: 0749aef = 92: 9bcbde4 gvfs-helper: better handling of network errors

  • 128: 7c82eb3 = 93: 2c7309f gvfs-helper-client: properly update loose cache with fetched OID

  • 129: 2adbc16 = 94: bc50122 gvfs-helper: V2 robust retry and throttling

  • 130: 2277caf = 95: 7941679 gvfs-helper: expose gvfs/objects GET and POST semantics

  • 131: f52091e = 96: 800b0cf gvfs-helper: dramatically reduce progress noise

  • 132: 0243158 = 97: 093a100 gvfs-helper: handle pack-file after single POST request

  • 133: dbe1bae = 98: 4bf7d7c test-gvfs-prococol, t5799: tests for gvfs-helper

  • 134: 040e897 = 99: 300abff gvfs-helper: move result-list construction into install functions

  • 135: db64064 = 100: 3560ea8 t5799: add support for POST to return either a loose object or packfile

  • 136: 833e2e6 = 101: 4cc9597 t5799: cleanup wc-l and grep-c lines

  • 137: 4a8645f = 102: 29a679c gvfs-helper: verify loose objects after write

  • 138: 116cea5 = 103: 891123a t7599: create corrupt blob test

  • 139: d53d9e3 = 104: ca9cfb1 gvfs-helper: add prefetch support

  • 140: 8e8fdbb = 105: bbd84e6 gvfs-helper: add prefetch .keep file for last packfile

  • 141: 5283a47 = 106: 56ef18f gvfs-helper: do one read in my_copy_fd_len_tail()

  • 142: 9f08dab = 107: 232317b gvfs-helper: move content-type warning for prefetch packs

  • 143: c1e461c = 108: ea27ffc fetch: use gvfs-helper prefetch under config

  • 144: 9a1b943 = 109: 0cf3c00 gvfs-helper: better support for concurrent packfile fetches

  • 145: 6962871 = 110: 6c8541f remote-curl: do not call fetch-pack when using gvfs-helper

  • 146: 0d25abb = 111: 1166f60 fetch: reprepare packs before checking connectivity

  • 147: e6f75ad = 112: 2491ae0 gvfs-helper: retry when creating temp files

  • 148: e954bda = 113: af15685 sparse: avoid warnings about known cURL issues in gvfs-helper.c

  • 154: 7be2e5c = 114: 5da56b5 gvfs-helper: add --max-retries to prefetch verb

  • 149: 3e7f3fd = 115: 5ab02ef maintenance: care about gvfs.sharedCache config

  • 150: cb3a5c1 = 116: 2c2b73a unpack-trees:virtualfilesystem: Improve efficiency of clear_ce_flags

  • 151: 350572e = 117: 7d0caa1 homebrew: add GitHub workflow to release Cask

  • 152: 46f15e2 = 118: 2f6134b Adding winget workflows

  • 153: 571b446 = 119: 4886553 Disable the monitor-components workflow in msft-git

  • 155: c6aa8f1 = 120: 5fd24b8 .github: enable windows builds on microsoft fork

  • 157: 81302ca = 121: 03d5cb2 .github/actions/akv-secret: add action to get secrets

  • 159: c4b4f7c = 122: 350183e release: create initial Windows installer build workflow

  • 161: cf32e69 = 123: 710ac20 release: create initial Windows installer build workflow

  • 163: 05a6f23 = 124: 49e7d81 help: special-case HOST_CPU universal

  • 165: 89a7ed6 = 125: 1a85ef3 release: add Mac OSX installer build

  • 167: abab2db = 126: 8258b21 release: build unsigned Ubuntu .deb package

  • 168: 55bd87c = 127: 5a56994 release: add signing step for .deb package

  • 156: 7664b9a = 128: f1f02d4 t5799: add tests to detect corrupt pack/idx files in prefetch

  • 170: b93b3de = 129: c4c3ee8 release: create draft GitHub release with packages & installers

  • 169: 35d9c4d = 130: d8bca3c update-microsoft-git: create barebones builtin

  • 158: 201f1a5 = 131: 3203055 gvfs-helper: ignore .idx files in prefetch multi-part responses

  • 172: 0d0387a = 132: 4f0d8df build-git-installers: publish gpg public key

  • 171: b1fea8f = 133: d20d97b update-microsoft-git: Windows implementation

  • 160: b8811a0 = 134: bd3c4a5 t5799: explicitly test gvfs-helper --fallback and --no-fallback

  • 174: 219b139 = 135: 34acde5 release: continue pestering until user upgrades

  • 173: 45d9338 = 136: 0e701d4 update-microsoft-git: use brew on macOS

  • 162: eac613c = 137: 5f0dd55 gvfs-helper: don't fallback with new config

  • 176: 9e28bca = 138: 2853f32 dist: archive HEAD instead of HEAD^{tree}

  • 175: 75a6401 = 139: 7b2cb62 .github: reinstate ISSUE_TEMPLATE.md for microsoft/git

  • 164: 40f1b63 = 140: a6bde35 test-gvfs-protocol: add cache_http_503 to mayhem

  • 178: 7d99d88 = 141: cb46a9b release: include GIT_BUILT_FROM_COMMIT in MacOS build

  • 177: 7e7a063 = 142: c644919 .github: update PULL_REQUEST_TEMPLATE.md

  • 166: 731f476 = 143: b9d3ba7 t5799: add unit tests for new gvfs.fallback config setting

  • 180: 302d10b = 144: 17c44f9 release: add installer validation

  • 58: 38b92fd = 145: 3d01dd5 git_config_set_multivar_in_file_gently(): add a lock timeout

  • 59: 5b68974 = 146: f298444 scalar: set the config write-lock timeout to 150ms

  • 60: 05640c1 = 147: c66ce1d scalar: add docs from microsoft/scalar

  • 61: c85e0cb = 148: 54dfd0a scalar (Windows): use forward slashes as directory separators

  • 62: b90e1b2 = 149: 2d24651 scalar: add retry logic to run_git()

  • 179: 51ce5a3 = 150: fba0bfa Adjust README.md for microsoft/git

  • 63: a1cef3a = 151: 201e87c scalar: support the config command for backwards compatibility

  • 181: 413344d = 152: 7c496d4 scalar: implement a minimal JSON parser

  • 182: bbb2c93 = 153: 0f178d7 scalar clone: support GVFS-enabled remote repositories

  • 183: eb850b1 = 154: 0ac4838 test-gvfs-protocol: also serve smart protocol

  • 184: 4b98ad9 = 155: 8bd4288 gvfs-helper: add the endpoint command

  • 185: dccad8b = 156: 84266a1 dir_inside_of(): handle directory separators correctly

  • 186: c618d9f = 157: b06c53d scalar: disable authentication in unattended mode

  • 187: 665dcba = 158: 1bf3ab1 abspath: make strip_last_path_component() global

  • 188: c058b25 = 159: a3760d3 scalar: do initialize gvfs.sharedCache

  • 189: ce927e6 = 160: 856fcdc scalar diagnose: include shared cache info

  • 190: e111532 = 161: d0cfcea scalar: only try GVFS protocol on https:// URLs

  • 191: 9371c15 = 162: 66ff167 scalar: verify that we can use a GVFS-enabled repository

  • 192: ffc1873 = 163: eff760c scalar: add the cache-server command

  • 193: f886527 = 164: df43053 scalar: add a test toggle to skip accessing the vsts/info endpoint

  • 194: 4cdb1f6 = 165: 4ef10ef scalar: adjust documentation to the microsoft/git fork

  • 195: 7b665d8 = 166: e83ebf7 scalar: enable untracked cache unconditionally

  • 196: 3ffb7c1 = 167: def21f4 scalar: parse clone --no-fetch-commits-and-trees for backwards compatibility

  • 197: 55f9157 = 168: 4604ac5 scalar: make GVFS Protocol a forced choice

  • 198: ef85362 = 169: 3332e4c scalar: work around GVFS Protocol HTTP/2 failures

  • 199: 05a005c = 170: eff10e1 gvfs-helper-client: clean up server process(es)

  • 200: ae955d0 = 171: 8cb1ce2 scalar diagnose: accommodate Scalar's Functional Tests

  • 201: 0037aab = 172: eb52c97 ci: run Scalar's Functional Tests

  • 203: e8a204b = 173: eac1fca add/rm: allow adding sparse entries when virtual

  • 202: 87c0320 = 174: 9222306 scalar: upgrade to newest FSMonitor config setting

  • 204: 1a38d33 = 175: 5bfb658 sparse-checkout: add config to disable deleting dirs

  • 205: 3ca5d4c = 176: f46c85b diff: ignore sparse paths in diffstat

  • 206: 76f7429 = 177: f3b016a repo-settings: enable sparse index by default

  • 64: 8b35499 = 178: f8e61ec TO-UPSTREAM: sequencer: avoid progress when stderr is redirected

  • 207: 33c4ac5 = 179: ee3a5b0 TO-CHECK: t1092: use quiet mode for rebase tests

  • 208: c588a1e = 180: 984dd0d reset: fix mixed reset when using virtual filesystem

  • 209: f5b0000 = 181: 1539785 diff(sparse-index): verify with partially-sparse

  • 210: 45a4e8b = 182: 2c8615f stash: expand testing for git stash -u

  • 211: 320dae9 = 183: 682b6fb sparse-index: add ensure_full_index_with_reason()

  • 212: d082dd2 = 184: d317712 treewide: add reasons for expanding index

  • 213: 090b316 = 185: 534667e treewide: custom reasons for expanding index

  • 214: db3a005 = 186: 6ae2584 sparse-index: add macro for unaudited expansions

  • 215: 7d70202 = 187: 6b3a33c Docs: update sparse index plan with logging

  • 216: f4215dc = 188: 96f3356 sparse-index: log failure to clear skip-worktree

  • 217: bbb626d = 189: 449b6be stash: use -f in checkout-index child process

  • 218: 2b210e8 = 190: 6f72510 sparse-index: do not copy hashtables during expansion

  • 219: e6e6df4 = 191: 0ffc366 TO-UPSTREAM: sub-process: avoid leaking cmd

  • 220: 8155039 = 192: 4c638a2 remote-curl: release filter options before re-setting them

  • 221: b1d2722 = 193: 2d58a31 transport: release object filter options

  • 222: 56e0d97 = 194: 9f2f4dc push: don't reuse deltas with path walk

  • 223: 623f76e = 195: b9ba9a5 t7900-maintenance.sh: reset config between tests

  • 224: 9cf29e3 = 196: 29e136b maintenance: add cache-local-objects maintenance task

  • 225: 6dade3f = 197: 7afb769 scalar.c: add cache-local-objects task

  • 226: 3db85bc = 198: 9123390 hooks: add custom post-command hook config

  • 227: 9b00a05 = 199: 003d902 TO-UPSTREAM: Docs: fix asciidoc failures from short delimiters

  • 228: d56af6f = 200: db54604 hooks: make hook logic memory-leak free

  • 15: f636816 = 201: 790603a revision: defensive programming

  • 16: e0315ad = 202: dece32b get_parent(): defensive programming

  • 17: 4a7f67b = 203: 5800645 fetch-pack: defensive programming

  • 32: b361e0f = 204: e2fc7b4 codeql: run static analysis as part of CI builds

  • 18: fd9d010 = 205: 93769c9 unparse_commit(): defensive programming

  • 33: b37754e = 206: 3670ee2 codeql: publish the sarif file as build artifact

  • 19: 0691fe8 = 207: 5c20b61 verify_commit_graph(): defensive programming

  • 34: 3a342c0 = 208: aa9009c codeql: disable a couple of non-critical queries for now

  • 20: 7835772 = 209: 3759357 stash: defensive programming

  • 13: 78b124a = 210: 22b6549 cat_one_file(): make it easy to see that the size variable is initialized

  • 35: ababb4a = 211: a0359b0 date: help CodeQL understand that there are no leap-year issues here

  • 26: 4fe23c9 = 212: 076e5a1 fetch: silence a CodeQL alert about a local variable's address' use after release

  • 21: bb5031b = 213: 0cbccd8 stash: defensive programming

  • 14: 652aa89 = 214: 1df1501 fsck: avoid using an uninitialized variable

  • 36: 59a23a2 = 215: 6b18a92 help: help CodeQL understand that consuming envvars is okay here

  • 27: fbdf66e = 216: a54c2ec submodule: check return value of submodule_from_path()

  • 22: 180bf17 = 217: 6a424a9 push: defensive programming

  • 23: 62a1904 = 218: acd367f load_revindex_from_disk(): avoid accessing uninitialized data

  • 37: b1d23ad = 219: aeaeeb1 ctype: help CodeQL understand that sane_istest() does not access array past end

  • 28: 8b53b0c = 220: 72da103 test-tool repository: check return value of lookup_commit()

  • 24: 02f3d94 = 221: 9af6dbe fetch: defensive programming

  • 25: beacd12 = 222: 04f2211 load_pack_mtimes_file(): avoid accessing uninitialized data

  • 38: d62134b = 223: b8418b2 ctype: accommodate for CodeQL misinterpreting the z in mallocz()

  • 29: c402925 = 224: dc79944 shallow: handle missing shallow commits gracefully

  • 30: 65281cb = 225: 59af17c inherit_tracking(): defensive programming

  • 39: 0b03b30 = 226: 44aa008 strbuf_read: help with CodeQL misunderstanding that strbuf_read() does NUL-terminate correctly

  • 31: 25fdfc6 = 227: 762710f commit-graph: suppress warning about using a stale stack addresses

  • 40: 38820bf = 228: ab096ca codeql: also check JavaScript code

  • 229: e03f7d1 < -: ----------- fixup! gvfs: add global command pre and post hook procs

Let's output the URL of the release that was just created; That will
make it more convenient to go from finished workflow run to publishing
the release.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
@dscho
Copy link
Member Author

dscho commented Nov 7, 2025

Note: I slipped in 7c92b3b, which adds a convenient message to the build-git-installer workflow's summary page that links to the created release. It is slightly inappropriate to slip in such a change in an -rc1 rebase, but then: This change matters most in the release phase, so this is the time to exercise that patch (and iterate on it if necessary).

derrickstolee and others added 3 commits November 10, 2025 08:17
When the top-level Git process is an alias, it doesn't load much config
and thus the postCommand.strategy config setting is not loaded properly.
This leads to the post-command hook being run more frequently than we want,
including an alias for 'git add' running the hook even when the worktree
did not change.

Similar state is not loaded by 'git version' or 'git typo'.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
When the post-command hook runs, we could be in several custom states:

1. The command is a regular builtin, but the repo setup is incomplete.
   (Example: "git version", "git rev-parse HEAD")

2. The command is a dashed command, but the top level process uses a space
   in its call. (Example: "git http-request")

3. The command is an alias that goes to a builtin.

4. The command has no arguments or is only helptext.

Each of these cases leads to a place where we previously had not loaded the
postCommand.strategy config and would execute the post-command hook without
looking for a sentinel file.

There are two fixes here:

First, we use early config parsing so we can get config details without
fully setting up the repository. This is how core.hooksPath works in these
situations.

Second, we need to make sure handle_hook_replacement() is called even when
the repo's gitdir is NULL. This requires a small amount of care to say that
a sentinel file cannot exist if the gitdir isn't set, as we would not have
written one without initializing the gitdir.

This gets all of the desired behaviors we want for this setting without
doing anything extreme with how pre- and post-command hooks run otherwise.

Signed-off-by: Derrick Stolee <stolee@gmail.com>
The postCommand.strategy=worktree-change config option allows for
skipping the post-command hook when the Git command doesn't change the
worktree. However, sometimes this config isn't loaded before the
post-command hook is invoked, causing the hook to run in cases where
we'd prefer it to not run.

Examples include: `git version` or `git <typo>`.

The tricky bit is that there are several places where we get here and
standard config mechanisms can't load due to not having a `gitdir` in
the repository struct. We fix this by:

1. Using the "load early config" mechanism also used by
`core.hooksPath`.
2. Skipping the lookup for the sentinel file when there isn't a `gitdir`
since we couldn't have written one without it.

The change is given in two commits: the first expands the tests with the
existing behavior and the second changes the behavior, showing the
impact on those tests.

* [X] This change only applies to microsoft/git specifics (post-command
hook)

See #736 and #748 for prior art in this space.
@dscho dscho marked this pull request as ready for review November 10, 2025 11:02
@dscho dscho merged commit 9c6b4d2 into vfs-2.52.0-rc1 Nov 10, 2025
297 of 303 checks passed
@dscho dscho deleted the tentative/vfs-2.52.0-rc1 branch November 10, 2025 11:31
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.