Skip to content

Fix duplicate commits from overlapping history refreshes (#563) - #564

Merged
hannesa2 merged 2 commits into
gitx:masterfrom
goneng:fix-duplicate-commits-race
Aug 9, 2026
Merged

hannesa2 merged 2 commits into
gitx:masterfrom
goneng:fix-duplicate-commits-race

Conversation

@goneng

@goneng goneng commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Fixes History view shows duplicate commit rows after rapid branch-changing git operations (e.g. git switch -c) #563: rapid successive git-directory changes (e.g. git switch -c <branch>) could trigger overlapping PBGitRevList parses, and a stale parse's trailing commit flush could land after a newer parse had already started, duplicating commits in the history list.
  • Guard PBGitRevList with a per-instance load generation: updateCommits:operation:generation: now rejects any flush whose generation no longer matches the current one, closing the race regardless of operation-queue/FSEvents timing.
  • Debounce PBGitHistoryController._repositoryUpdatedNotification: so a burst of git-directory FSEvents (e.g. the ref-file write and HEAD rewrite from a single git switch -c) collapses into one refresh: call.

Test plan

  • xcodebuild -project GitX.xcodeproj -scheme GitX -configuration Debug -destination 'platform=macOS' build succeeds.
  • lldb breakpoints on -[PBGitHistoryList updateProjectHistoryForRev:], -[PBGitRevList loadRevisionsWithCompletionBlock:], and -[PBGitRevList updateCommits:operation:generation:] resolve at the expected source lines in the built binary, confirming the generation-guard code is live.
  • Manual repro: launch the built app against a throwaway repo and run a burst of rapid git switch -c calls while watching the commit list ("All" scope) for duplicate rows.

goneng added 2 commits August 9, 2026 15:13
A burst of git-directory FSEvents (e.g. from `git switch -c <branch>`
touching both a ref file and HEAD) can trigger overlapping
loadRevisionsWithCompletionBlock: calls on the same PBGitRevList
instance. The previous parse operation's trailing commit-batch flush
is fire-and-forget and can still land after a newer parse has already
reset/appended its own commits, since NSOperation.isCancelled is only
checked cooperatively and can lose that race. The result is duplicate
commits appended into the history list.

Track a per-instance load generation and reject any updateCommits:
flush whose generation no longer matches the current one, closing the
race regardless of operation-queue/FSEvents timing.
FSEvents' coalescing window doesn't reliably batch every file written
by a single git operation (e.g. `git switch -c` writes a new ref file
and rewrites HEAD) into one callback, so PBGitHistoryController could
receive multiple PBGitRepositoryEventNotifications in quick succession
and call refresh: for each one, triggering redundant, overlapping
history reloads.

Coalesce bursts of git-directory notifications within a short window
into a single refresh: call, and cancel any pending debounced refresh
when the view closes.
@hannesa2 hannesa2 added the bugfix label Aug 9, 2026
@hannesa2
hannesa2 merged commit 4d79978 into gitx:master Aug 9, 2026
3 checks passed
@goneng
goneng deleted the fix-duplicate-commits-race branch August 9, 2026 17:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

History view shows duplicate commit rows after rapid branch-changing git operations (e.g. git switch -c)

2 participants