Skip to content

Conversation

@gadfly3173
Copy link
Contributor

In some cases, WorkingCopy view fails to refresh after commit due to a race condition between FileSystemWatcher, manual refresh calls, and the IsChanged optimization in SetData().

Problem analysis by Claude:

Problem

After committing changes, the staged/unstaged files in WorkingCopy view sometimes remain visible instead of being cleared, even when manually calling RefreshAll().

Root Cause

This is caused by a race condition between multiple asynchronous refresh mechanisms:

  1. During commit, LockWatcher() prevents FileSystemWatcher from processing git file changes
  2. After commit, MarkBranchesDirtyManually() is called, which:
    • Calls MarkBranchUpdated() setting _updateBranch = 0
    • Triggers RefreshWorkingCopyChanges() asynchronously
  3. Race condition occurs when:
    • The async query completes and returns an empty change list (correct - nothing to commit now)
    • But WorkingCopy._cached happens to also be empty (from a previous refresh)
    • SetData() checks IsChanged(_cached, changes) which returns false for ([], [])
    • UI is not updated because the method returns early

This timing issue is difficult to reproduce consistently but happens when:

  • Multiple refresh calls cancel each other via CancellationToken
  • The _cached state happens to match the new query result
  • FileSystemWatcher events are delayed or processed out of order

Solution

Call MarkWorkingCopyDirtyManually() after commit to ensure WorkingCopy refresh is properly triggered:

_repo.MarkBranchesDirtyManually();
_repo.MarkWorkingCopyDirtyManually();  // Ensure WorkingCopy refresh
IsCommitting = false;

This additional call:

  • Resets Watcher state (_updateWC = 0) to clear any pending delayed refresh
  • Starts a fresh RefreshWorkingCopyChanges() task
  • Guarantees the refresh happens regardless of race conditions
  • Makes the intent explicit: commit requires WorkingCopy refresh

Testing

The issue is hard to reproduce consistently due to timing dependencies, but the fix:

  • Adds minimal overhead (one extra refresh call)
  • Does not break any existing logic
  • Covers all edge cases where the original refresh might fail

In some cases, WorkingCopy view fails to refresh after commit due to
a race condition between FileSystemWatcher, manual refresh calls, and
the IsChanged optimization in SetData().
@love-linger
Copy link
Collaborator

Since MarkBranchesDirtyManually will call RefreshWorkingCopyChanges manually and Watcher has been stopped at that point, I think it's better to just reset _updateWC in MarkBranchUpdated

@gadfly3173 gadfly3173 closed this Nov 7, 2025
@gadfly3173 gadfly3173 deleted the fix/commit branch November 7, 2025 08:52
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.

2 participants