fix: allow checkout with non-conflicting dirty tracked files#35
Merged
alexandreafj merged 1 commit intoMay 19, 2026
Merged
Conversation
gitm checkout was unconditionally skipping repos with any modified tracked
files, even when git itself would allow the branch switch (e.g. a modified
file that is identical on both branches). This made gitm stricter than
native git and blocked common workflows like switching branches with a
locally-modified .npmrc.
Instead of pre-checking dirty state, attempt the checkout and only skip
when git reports an actual conflict ("Your local changes would be
overwritten"). This delegates conflict detection to git's own merge logic.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Allows gitm checkout to proceed when dirty tracked files do not conflict with the target branch, matching git checkout semantics. Previously, any dirty tracked file caused an unconditional skip.
Changes:
- Removed pre-checkout
IsDirtyTrackedOnlycheck from bothrunCheckoutDefaultandcheckoutBranchInRepo. - Added
isCheckoutConflictandcheckoutConflictSkiphelpers to detect git's "local changes would be overwritten" errors and skip only in that case. - Updated/added unit and E2E tests covering conflicting vs. non-conflicting dirty-file scenarios.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| internal/cli/checkout.go | Replaces dirty-check skip with attempt-then-detect-conflict approach; adds conflict detection helpers; updates command long description. |
| internal/cli/checkout_run_test.go | Adds unit tests for the new behavior across default, interactive, and helper code paths, plus tests for helpers. |
| internal/e2e/checkout_test.go | Replaces TestCheckout_DirtyRepo_Skips with separate non-conflicting (succeeds) and conflicting (skips) E2E tests. |
|
✅ All checks passed (Go 1.26) Coverage: 69.1% |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Your local changes would be overwritten)git checkoutworks (e.g. modified.npmrcidentical on both branches) butgitm checkoutrefusedWhat changed
gitm checkoutrunsgit status --porcelain -unobefore checkout; any dirty tracked file → skipgitm checkoutattemptsgit checkoutdirectly; only skips on conflict error from gitNew helpers:
isCheckoutConflict(err)— detects git's "Your local changes would be overwritten" errorscheckoutConflictSkip(path, err)— builds the skip reason with dirty file listTest plan
TestRunCheckoutDefault_NonConflictingDirtyFile— dirty file identical on both branches → checkout succeedsTestRunCheckoutDefault_ConflictingDirtyFile— dirty file differs between branches → skip (not error)TestCheckoutBranchInRepo_NonConflictingDirtyFile— same viacheckoutBranchInRepoTestCheckoutBranchInRepo_ConflictingDirtyFile— same viacheckoutBranchInRepoTestCheckoutInteractive_NonConflictingDirtyFile— interactive mode with non-conflicting dirtyTestCheckoutDefault_MultipleReposMixedDirtyState— 3 repos: clean, conflicting, non-conflictingTestIsCheckoutConflict— unit test for conflict detectionTestCheckoutConflictSkip_NonConflictError— non-conflict errors pass throughTestCheckout_DirtyRepo_NonConflicting_Succeeds(replaces oldTestCheckout_DirtyRepo_Skips)TestCheckout_DirtyRepo_Conflicting_Skips— new e2e for actual conflicts-racemake lintpasses🤖 Generated with Claude Code