From ee3e8f00c831eff24152715b1060a793b0f16bff Mon Sep 17 00:00:00 2001 From: Corentin Damman Date: Wed, 30 Sep 2026 10:18:42 +0200 Subject: [PATCH] fix: watcher missed ref updates stored in `packed-refs` or lost on buffer overflow The branch graph was sometimes not updated after a fetch, until a pull or a restart. - `packed-refs` was ignored. A ref updated or deleted only there (e.g. `fetch --prune`, or the `git maintenance run --auto` triggered after a fetch) never scheduled a refresh. - `FileSystemWatcher.Error` was not handled. A large fetch writes thousands of object files, which overflows the internal buffer (8 KB by default): Windows then drops events, including the ones about `refs/remotes/*`, and nothing noticed. Since we cannot know which events were lost, schedule a full reload instead. --- src/Models/Watcher.cs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Models/Watcher.cs b/src/Models/Watcher.cs index b881807b0c..66e246bc07 100644 --- a/src/Models/Watcher.cs +++ b/src/Models/Watcher.cs @@ -43,6 +43,7 @@ public Watcher(IRepository repo, string fullpath, string gitDir) combined.Renamed += OnRepositoryChanged; combined.Changed += OnRepositoryChanged; combined.Deleted += OnRepositoryChanged; + combined.Error += OnWatcherError; combined.EnableRaisingEvents = false; _watchers.Add(combined); @@ -58,6 +59,7 @@ public Watcher(IRepository repo, string fullpath, string gitDir) wc.Renamed += OnWorkingCopyChanged; wc.Changed += OnWorkingCopyChanged; wc.Deleted += OnWorkingCopyChanged; + wc.Error += OnWatcherError; wc.EnableRaisingEvents = false; var git = new FileSystemWatcher(); @@ -69,6 +71,7 @@ public Watcher(IRepository repo, string fullpath, string gitDir) git.Renamed += OnGitDirChanged; git.Changed += OnGitDirChanged; git.Deleted += OnGitDirChanged; + git.Error += OnWatcherError; git.EnableRaisingEvents = false; _watchers.Add(wc); @@ -240,6 +243,21 @@ private void OnRepositoryChanged(object o, FileSystemEventArgs e) HandleWorkingCopyFileChanged(name, e.FullPath); } + /// + /// The internal buffer overflowed (a large fetch or checkout writes thousands of files), so + /// some events were dropped and we cannot know which. Reload everything once things settle. + /// + private void OnWatcherError(object o, ErrorEventArgs e) + { + var desired = DateTime.Now.AddSeconds(1).ToFileTime(); + Interlocked.Exchange(ref _updateBranch, desired); + Interlocked.Exchange(ref _updateTags, desired); + Interlocked.Exchange(ref _updateStashes, desired); + Interlocked.Exchange(ref _updateWC, desired); + if (_repo.MayHaveSubmodules()) + Interlocked.Exchange(ref _updateSubmodules, desired); + } + private void OnGitDirChanged(object o, FileSystemEventArgs e) { if (string.IsNullOrEmpty(e.Name)) @@ -302,6 +320,12 @@ private void HandleGitDirFileChanged(string name) { Interlocked.Exchange(ref _updateBranch, DateTime.Now.AddSeconds(.5).ToFileTime()); } + else if (name.Equals("packed-refs", StringComparison.Ordinal)) + { + var desired = DateTime.Now.AddSeconds(.5).ToFileTime(); + Interlocked.Exchange(ref _updateBranch, desired); + Interlocked.Exchange(ref _updateTags, desired); + } else if (name.StartsWith("reftable/", StringComparison.Ordinal)) { var desired = DateTime.Now.AddSeconds(.5).ToFileTime();