Skip to content

Offer to discard local changes when they block a checkout - #2840

Open
NikKovIos wants to merge 1 commit into
git-up:masterfrom
NikKovIos:feature/discard-changes-on-checkout
Open

NikKovIos wants to merge 1 commit into
git-up:masterfrom
NikKovIos:feature/discard-changes-on-checkout

Conversation

@NikKovIos

@NikKovIos NikKovIos commented Oct 29, 2026 •

Copy link
Copy Markdown
Contributor

Problem

When you check out a branch or a commit and uncommitted changes would be overwritten, GitUp only shows "Local changes would be overwritten by checkout" with an OK button. To switch anyway you have to discard or stash the changes yourself and then start the checkout again.

Changes

  • The alert now has Discard Changes and Continue and Cancel. Discarding runs the same checkout again with kGCCheckoutOption_Force, like git checkout -f:
    • every uncommitted change to tracked files, staged or not, is reverted, including in submodules;
    • untracked files that are in the way are overwritten, other untracked files are kept.
  • The button is destructive and doesn't respond to Return, and the alert says that this can't be undone. Undo in GitUp still moves back to the previous branch, but it can't bring the discarded changes back.
  • This applies to checking out a local branch, checking out a commit (detached HEAD), and Create Local Branch / Checkout New Tracking Local Branch for a remote branch. When the first attempt fails, the new local branch is deleted as before, and the retry creates it again.
  • Submodules are updated after HEAD has moved, so when only a submodule blocks the checkout, HEAD has already changed by the time the conflict is reported. A retry could then not be undone back to the previous HEAD, so in that case the error is presented as before, without the discard option.
  • Other errors are presented as before. Creating a branch with Checkout checked is not changed.
  • The app change is all in GCLiveRepository+Utilities.m, the header is unchanged.

Screenshots

Before

gitup-checkout-conflict-before

After

gitup-checkout-conflict-after

Tests

New GitUpKit/Extensions/GCLiveRepository+Utilities-Tests.m with 8 tests on a temporary repository:

  • the alert offers Discard Changes and Continue and Cancel, the discard button is destructive and not bound to Return, and the text says that this can't be undone;
  • discarding checks out a local branch, reverts staged and unstaged changes, overwrites an untracked file that is in the way and keeps other untracked files;
  • the same works for a commit (detached HEAD) and for Create Local Branch, which ends up tracking the remote branch;
  • Cancel keeps the current branch and the local changes;
  • other checkout errors (a branch checked out in another worktree) are presented as before, without the discard option;
  • when only a submodule blocks the checkout, the error is presented as before, without the discard option, for a local branch, a commit and Create Local Branch. The submodule is cloned from a local repository, so no network is needed.

The tests record sheet alerts by swapping -[NSAlert beginSheetModalForWindow:completionHandler:] for the duration of each test. The Tests target now also builds GCLiveRepository+Utilities.m and GIAppKit.m. That header is not public and the target builds without the AppKit part of GitUpKit.h, so a small header in Extensions/TestHeaders provides it to the Tests target only.

The full GitUpKit (macOS) suite runs 104 tests. Locally, testClone (needs SSH access to GitHub) and testDateFormatting (depends on the current date) fail, the same way as on master.

Testing

  • Builds cleanly (Application scheme, Debug).
  • Checked in the app on a repository with a modified tracked file and an unrelated untracked file:
    • Cancel leaves the branch and the working directory as they were;
    • Discard Changes and Continue switches to the branch, the tracked file matches the branch, and the untracked file is still there;
    • the same works for Checkout Commit (detached HEAD) and for Create Local Branch from a remote branch, which ends up tracking it;
    • without local changes, checkout works as before, with no alert.

I AGREE TO THE GITUP CONTRIBUTOR LICENSE AGREEMENT

@greptile-apps

greptile-apps Bot commented Oct 29, 2026 •

Copy link
Copy Markdown

RetriggerView in GreptileConfidence Score: 5/5

[Medium impact] The PR appears safe to merge; the previous unsafe retry is blocked, and no new actionable issues were found.

Summary

Adds a choice to discard local changes when they block checkout.

  • Checkout conflicts now offer a choice to discard changes and continue.

Runtime tests and visual checks were not run; this environment is Linux and cannot run the AppKit application.

Reviews (2) · Last reviewed commit: "Offer to discard local changes when they..." · Reviewed by Greptile

When checking out a local branch, a commit, or a new local branch that tracks a remote branch fails because uncommitted changes would be overwritten, the alert used to have only an OK button. It now offers "Discard Changes and Continue", which runs the same checkout again with kGCCheckoutOption_Force like "git checkout -f": uncommitted changes to tracked files are reverted, including in submodules, untracked files that are in the way are overwritten, and other untracked files are kept. The button is destructive, is not triggered by Return, and the alert warns that this cannot be undone. Other checkout errors are presented as before.

Submodules are updated after HEAD has moved, so when only a submodule blocks the checkout, HEAD has already changed by the time the conflict is reported. A retry could then not be undone back to the previous HEAD, so in that case the error is presented as before.

The new tests build GCLiveRepository+Utilities.m and GIAppKit.m in the Tests target. GCLiveRepository+Utilities.h is not a public header and the Tests target builds without the AppKit part of GitUpKit.h, so a small header in Extensions/TestHeaders provides it to that target only.
@NikKovIos
NikKovIos force-pushed the feature/discard-changes-on-checkout branch from aec3de9 to dcfe062 Compare October 29, 2026 14:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant