Skip to content

Offer a force push with lease when a push is rejected - #749

Merged
hannesa2 merged 1 commit into
masterfrom
force-push-with-lease
Oct 3, 2026
Merged

hannesa2 merged 1 commit into
masterfrom
force-push-with-lease

Conversation

@goneng

@goneng goneng commented Oct 3, 2026 •

Copy link
Copy Markdown
Collaborator

Stop sending users to the terminal after a rebase or amend: when git rejects a push as non-fast-forward, offer to retry it with --force-with-lease.

  • Show "Force Push (with Lease)" or "Cancel" after a (non-fast-forward) or (fetch first) rejection. Cancel is the default button.
  • Reuse the existing dialog suppression (Force Push With Lease): ticking the checkbox retries without asking, and Reset Warnings in the preferences brings the alert back.
  • Pass the remote-tracking SHA seen before the first attempt as the expected value (--force-with-lease=<branch>:<sha>, read on the push thread), so a fetch while the alert is open cannot weaken the lease.
  • Offered for local branches with a known remote-tracking SHA only. Tags and "push all" show the plain error, and so does a (stale info) refusal of the lease itself.

No new menu entries. Other clients were compared first: Tower has menu entries, GitKraken a banner after a diverged push; this follows the latter.

Test plan

  • New PBGitRepositoryForcePushTests: rejection detection, plus two tests against real local repos (rewritten branch is rejected then forced through; the lease refuses after someone else pushed). All 8 pass; the fixtures isolate git config like the other suites.
  • Manual, in a Debug build on a scratch repo with a local bare remote: amend a pushed commit and push from the sidebar; the alert shows the expected text with Cancel as the default, Cancel leaves the remote unchanged, and Force Push (with Lease) updates it. With "Don't ask again" ticked, the next rejected push goes through without the alert. Verified through accessibility queries and a visual check of the wording and layout. Reset Warnings was not tried.

@goneng
goneng marked this pull request as ready for review October 3, 2026 09:20
@goneng
goneng force-pushed the force-push-with-lease branch from f60e9ee to c5bdef3 Compare October 3, 2026 09:22
@goneng
goneng requested a review from hannesa2 October 3, 2026 09:24
@hannesa2
hannesa2 requested a balanced review from Copilot October 3, 2026 09:44

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

A missing SHA snapshot permits an unsafe implicit lease, while synchronous lookup and inherited test configuration need correction.

Review effort: Balanced
Findings: 1 High severity · 2 Medium severity

Open (3)
What changed in this PR

Adds an in-app force-with-lease retry for rejected local-branch pushes in GitX.

Changes:

  • Adds a suppressible confirmation with Cancel as the default.
  • Captures the remote-tracking SHA before pushing and adds lease-aware retries.
  • Adds rejection-detection and repository integration tests.
File Description
GitXTests/​PBGitRepositoryForcePushTests.m Tests rejection detection and lease behavior.
GitX.xcodeproj/​project.pbxproj Registers the new tests.
Classes/​git/​PBGitRepository.m Implements SHA lookup, lease arguments, and rejection detection.
Classes/​git/​PBGitRepository.h Exposes lease-related repository methods.
Classes/​Controllers/​PBGitWindowController.m Adds confirmation and retry handling.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread Classes/git/PBGitRepository.m Resolved
{
NSTask *task = [[NSTask alloc] init];
task.executableURL = [NSURL fileURLWithPath:@"/usr/bin/git"];
task.arguments = [@[ @"-c", @"user.name=Test", @"-c", @"[email protected]" ] arrayByAddingObjectsFromArray:arguments];
@hannesa2

hannesa2 commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Does the copilot suggestions make sense to you ?

Stop sending users to the terminal after a rebase or amend: when git
rejects a push as non-fast-forward, offer to retry it with a lease.

- Show "Force Push (with Lease)" or "Cancel" after such a rejection.
  Cancel is the default button.
- Reuse the existing dialog suppression, so ticking "do not show again"
  retries without asking and Reset Warnings brings the alert back.
- Pass the remote-tracking SHA seen before the first attempt as the
  expected value, so a fetch while the alert is open cannot weaken the
  lease. Read it on the push thread, not the main thread.
- Offer it for local branches with a known remote SHA only, and not
  after a stale lease.
@goneng
goneng force-pushed the force-push-with-lease branch from c5bdef3 to 54cbdf2 Compare October 3, 2026 10:53
@goneng

goneng commented Oct 3, 2026

Copy link
Copy Markdown
Collaborator Author

Yes, all three make sense and I've fixed them (force-pushed into the same commit). (1) The lease is now always explicit, so a fetch while the alert is open can't loosen it, and the alert isn't offered when GitX has no remote-tracking SHA. (2) The SHA lookup now runs in the background push block instead of on the main thread. (3) The test fixtures now isolate git config like the other suites. Added a test for the no-SHA case.

{
NSAlert *alert = [[NSAlert alloc] init];
alert.messageText = [NSString stringWithFormat:NSLocalizedString(@"Push of branch “%@” was rejected", @"Force push alert - message"), branchRef.shortName];
alert.informativeText = NSLocalizedString(@"The remote has commits this branch does not have. A force push replaces them, but only if the remote is still where GitX last saw it (git push --force-with-lease).", @"Force push alert - informative text");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--force-with-lease is a nice feature

@hannesa2
hannesa2 merged commit 4a4cf79 into master Oct 3, 2026
3 checks passed
@hannesa2
hannesa2 deleted the force-push-with-lease branch October 3, 2026 14:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants