What's wrong
The two pull buttons take different paths:
- Pull (per repository) goes through
PullRepoConfirmingUncommittedChanges. That calls DecidePull, and when git status --porcelain reports changes it asks "Pull anyway?" (ProjectDirector/ProjectDirector.cs:463-496, pinned by PullDecisionTests).
- Pull All (left panel,
ProjectDirector.cs:829-832) calls PullAllRepos, which is Options.ClonedRepos.Values.ForEach(PullRepo) (:402). That goes straight to PullRepo(GitRepository) and runs git pull --ff-only in every cloned repository. DecidePull is never consulted.
Failure scenario
- Edit a file in two cloned repositories and leave the edits uncommitted.
- Click Pull on one of them. The "Uncommitted Changes" prompt appears.
- Click Pull All. Both repositories are pulled at once, with no prompt.
What happens next depends on whether the upstream change touches the edited file:
That is the situation the per-repo confirmation exists to warn about: "Pulling now may fail partway or leave the working tree in a confusing state".
Suggested fix
Route Pull All through the same decision:
- Call
DecidePull for each repository.
- Pull the clean ones.
- For the dirty ones, either skip them and log "skipped : uncommitted changes", or show one confirmation that lists them all.
Extract the split as a pure method, such as PartitionForPullAll(repos) -> (clean, dirty), and cover it in PullDecisionTests, following CLAUDE.md's pattern for testable rules.
Acceptance criteria
- Pull All never pulls a repository for which
DecidePull returns Confirm unless the user has agreed, either for the batch or for that repository.
- Skipped repositories are named in the log.
- The partition is covered by a test against throwaway repositories.
What's wrong
The two pull buttons take different paths:
PullRepoConfirmingUncommittedChanges. That callsDecidePull, and whengit status --porcelainreports changes it asks "Pull anyway?" (ProjectDirector/ProjectDirector.cs:463-496, pinned byPullDecisionTests).ProjectDirector.cs:829-832) callsPullAllRepos, which isOptions.ClonedRepos.Values.ForEach(PullRepo)(:402). That goes straight toPullRepo(GitRepository)and runsgit pull --ff-onlyin every cloned repository.DecidePullis never consulted.Failure scenario
What happens next depends on whether the upstream change touches the edited file:
That is the situation the per-repo confirmation exists to warn about: "Pulling now may fail partway or leave the working tree in a confusing state".
Suggested fix
Route Pull All through the same decision:
DecidePullfor each repository.Extract the split as a pure method, such as
PartitionForPullAll(repos) -> (clean, dirty), and cover it inPullDecisionTests, following CLAUDE.md's pattern for testable rules.Acceptance criteria
DecidePullreturnsConfirmunless the user has agreed, either for the batch or for that repository.