Repository navigation
Fix remote-branch delete doing nothing, and expose prune-on-fetch - #570
Merged
Merged
Conversation
goneng
force-pushed
the
fix-remote-branch-delete-and-prune
branch
6 times, most recently
from
August 11, 2026 23:11
af77480 to
675635b
Compare
-deleteRef: filtered the sender's ref through a type list that omitted kGitXRemoteBranchType, so it returned before ever reaching git. - Add -deleteRemoteBranch:error:, running "git push <remote> --delete <branch>" through the progress sheet already used by push and pull - Route remote branches in -deleteRef: ahead of the remote check, since isRemote is true both for a remote and for a branch under it - Confirm without a suppression identifier, and default both delete alerts to Cancel with Delete marked destructive - Title the item Delete "branch" on "remote", and correct the menu's localization comments, which described the wrong cases
Branches deleted upstream lingered in the sidebar indefinitely: GitX never pruned, and fetch.prune had no UI anywhere in the app. - Add a fetch.prune row to the Git Preferences dialog, repository and global, tri-state like the other booleans there - Add a General preference offering use git config (the default), always prune, or never prune - Pass --prune or --no-prune to git fetch accordingly, leaving the default case for fetch.prune and remote.<name>.prune to decide
Both preference windows left the key view loop unreachable on open, and kept drawing the previous tab as selected when a pane was activated from the keyboard. - Point the window's initialFirstResponder at the first control that accepts focus rather than at the pane container, which never does, so Tab has a way into a freshly shown pane and lands in the pane on display rather than restarting at the first toolbar item - Recalculate the key view loop once the pane is in the hierarchy, so that lookup sees the controls it is about to order - Set the toolbar's selected item wherever a pane is displayed rather than only when the window opens; AppKit syncs the selection for a mouse click but not for a keyboard activation The focus ring is still dropped on every pane swap, as it always was.
goneng
force-pushed
the
fix-remote-branch-delete-and-prune
branch
from
August 12, 2026 00:11
675635b to
a65558f
Compare
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.
Deleting a branch under a remote in the sidebar did nothing at all, and separately, branches deleted upstream never disappeared from the sidebar.
The delete bug
-deleteRef:filtered the sender's ref throughrefishForSender:refishTypes:with@[branch, remote, tag]. A ref under a remote reportskGitXRemoteBranchType, which was not in that list, so the method returned before ever reaching git: no confirmation dialog, no error, nothing logged. The remote node itself iskGitXRemoteType, which is why "Delete origin..." worked and made the failure look inconsistent rather than total.Remote branches now run
git push <remote> --delete <branch>through the same progress sheet as push and pull. The routing inPBGitRepository -deleteRef:checks for a remote branch before the remote check, becauseisRemoteis true both forrefs/remotes/originand forrefs/remotes/origin/branch; without that ordering a branch delete would have removed the entire remote.Because this now deletes on the server, the confirmation passes a
nilsuppression identifier.-confirmDialog:suppressionIdentifier:forAction:skips the dialog outright once an identifier has been suppressed, so sharing"Delete Ref"with local deletes would have let anyone who ticked "do not show again" trigger silent server-side deletes. Both delete alerts also default to Cancel now, with Delete marked destructive.The stale refs
GitX ran
git fetch <remote>with no--prune, and nothing in the codebase pruned. Since GitX shells out to plain git with no-coverrides,fetch.prunealready worked; it simply had no UI. Two layers now:fetch.pruneis a row in the Git Preferences dialog, repository and global, tri-state like the other booleans there.--prune/--no-prune/ nothing. The default keeps the git config setting authoritative.Git Preferences dialog, while we were in there
<repo> Prefs.andGlobal Prefs.. This window has no room for a title of its own, so the labels carry both.Rebase on PullandPrune on Fetchsit together, just aboveSummarize Merge Commits.Test plan
git push origin --delete <branch>removes the branch upstream and drops the local tracking ref on its own; a plain fetch leaves a stale ref,--pruneremoves it,fetch.prune=trueprunes on a plain fetch, and--no-prunekeeps the stale ref even withfetch.prune=true.Keyboard focus in the preference windows
Found while reviewing the panes above, and shared by both preference windows since they are both built on
DBPrefsWindowController.initialFirstResponderwas set to the pane's container view, which never accepts focus, so Tab went to the window and stopped. Git Preferences escaped this by luck of geometry, its first control being a plain text field. Fixed by recalculating the key view loop once the pane is in the hierarchy and starting it at the first control that actually takes focus. This also means that after switching panes, Tab continues into the pane on display instead of restarting at the first toolbar item.setSelectedItemIdentifier:was only called when the window opened. AppKit moves the selection itself when an item is clicked, but not when it is activated from the keyboard, so the previously selected tab kept its selected styling while a different pane was displayed. The selection is now set wherever a pane is displayed, which covers every route in.The focus ring is still dropped on every pane swap, unchanged from before. Return is deliberately left alone; note that in Git Preferences it triggers Save and closes the dialog, since Save carries the Return key equivalent.
Measured by driving the app from the keyboard, before and after: