From 158029dbf29243275d5748997f4ee515bdce3423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tr=C6=B0=C6=A1ng=20Duy=20Kh=C3=A1nh?= Date: Mon, 10 Aug 2026 11:08:48 +0700 Subject: [PATCH] Always prompt for the upstream when pushing the selected branch (#4) * Revert "Always confirm before pushing the selected branch (#3)" This reverts commit 619bbf71c7d177f23cfae4ee754d2ea0c5a8472f. * Always prompt for the upstream when pushing the selected branch A plain yes/no confirmation doesn't let the user catch or fix a wrong target before pushing. Reuse the same upstream-entry prompt already shown for a branch with no upstream configured, but always show it for a selected-branch push, pre-filled with the branch's current upstream (or a suggested one if it has none). Confirming pushes to whatever's typed there, and re-establishes it as the branch's tracking upstream. --------- Co-authored-by: Khanh Truong --- docs-master/keybindings/Keybindings_en.md | 2 +- docs-master/keybindings/Keybindings_ja.md | 2 +- docs-master/keybindings/Keybindings_ko.md | 2 +- docs-master/keybindings/Keybindings_nl.md | 2 +- docs-master/keybindings/Keybindings_pl.md | 2 +- docs-master/keybindings/Keybindings_pt.md | 2 +- docs-master/keybindings/Keybindings_ru.md | 2 +- docs-master/keybindings/Keybindings_zh-CN.md | 2 +- docs-master/keybindings/Keybindings_zh-TW.md | 2 +- pkg/gui/controllers/branches_controller.go | 22 ++++----- .../controllers/helpers/upstream_helper.go | 6 ++- pkg/gui/controllers/sync_controller.go | 46 +++++++++++-------- pkg/i18n/english.go | 4 +- 13 files changed, 49 insertions(+), 47 deletions(-) diff --git a/docs-master/keybindings/Keybindings_en.md b/docs-master/keybindings/Keybindings_en.md index 02f59f4ee..e5ec04e59 100644 --- a/docs-master/keybindings/Keybindings_en.md +++ b/docs-master/keybindings/Keybindings_en.md @@ -198,7 +198,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` R `` | Rename branch | | | `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. | | `` `` | Open external diff tool (git difftool) | | -| `` P `` | Push selected branch | Push the selected branch to its upstream branch, after confirming. If no upstream is configured, you will be prompted to configure an upstream branch. | +| `` P `` | Push selected branch | Push the selected branch, after confirming its upstream (pre-filled with what's already configured, or a suggestion if none is). | | `` p `` | Pull selected branch | Pull the selected branch's upstream branch into it, via its linked worktree. If no upstream is configured, you will be prompted to configure an upstream branch. | | `` 0 `` | Focus main view | | | `` `` | View commits | | diff --git a/docs-master/keybindings/Keybindings_ja.md b/docs-master/keybindings/Keybindings_ja.md index 28b992b31..dfe37e09c 100644 --- a/docs-master/keybindings/Keybindings_ja.md +++ b/docs-master/keybindings/Keybindings_ja.md @@ -396,7 +396,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` R `` | ブランチ名を変更 | | | `` u `` | アップストリームオプションを表示 | ブランチのアップストリームに関連するオプションを表示します(例:アップストリームの設定/解除やアップストリームへのリセット)。 | | `` `` | 外部差分ツールを開く(git difftool) | | -| `` P `` | Push selected branch | Push the selected branch to its upstream branch, after confirming. If no upstream is configured, you will be prompted to configure an upstream branch. | +| `` P `` | Push selected branch | Push the selected branch, after confirming its upstream (pre-filled with what's already configured, or a suggestion if none is). | | `` p `` | Pull selected branch | Pull the selected branch's upstream branch into it, via its linked worktree. If no upstream is configured, you will be prompted to configure an upstream branch. | | `` 0 `` | メインビューにフォーカス | | | `` `` | コミットを表示 | | diff --git a/docs-master/keybindings/Keybindings_ko.md b/docs-master/keybindings/Keybindings_ko.md index b2a8bd33c..319934518 100644 --- a/docs-master/keybindings/Keybindings_ko.md +++ b/docs-master/keybindings/Keybindings_ko.md @@ -230,7 +230,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` R `` | 브랜치 이름 변경 | | | `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. | | `` `` | Open external diff tool (git difftool) | | -| `` P `` | Push selected branch | Push the selected branch to its upstream branch, after confirming. If no upstream is configured, you will be prompted to configure an upstream branch. | +| `` P `` | Push selected branch | Push the selected branch, after confirming its upstream (pre-filled with what's already configured, or a suggestion if none is). | | `` p `` | Pull selected branch | Pull the selected branch's upstream branch into it, via its linked worktree. If no upstream is configured, you will be prompted to configure an upstream branch. | | `` 0 `` | Focus main view | | | `` `` | 커밋 보기 | | diff --git a/docs-master/keybindings/Keybindings_nl.md b/docs-master/keybindings/Keybindings_nl.md index 3cb9fcb30..d9d4ad7e4 100644 --- a/docs-master/keybindings/Keybindings_nl.md +++ b/docs-master/keybindings/Keybindings_nl.md @@ -121,7 +121,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` R `` | Hernoem branch | | | `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. | | `` `` | Open externe diff applicatie (git difftool) | | -| `` P `` | Push selected branch | Push the selected branch to its upstream branch, after confirming. If no upstream is configured, you will be prompted to configure an upstream branch. | +| `` P `` | Push selected branch | Push the selected branch, after confirming its upstream (pre-filled with what's already configured, or a suggestion if none is). | | `` p `` | Pull selected branch | Pull the selected branch's upstream branch into it, via its linked worktree. If no upstream is configured, you will be prompted to configure an upstream branch. | | `` 0 `` | Focus main view | | | `` `` | Bekijk commits | | diff --git a/docs-master/keybindings/Keybindings_pl.md b/docs-master/keybindings/Keybindings_pl.md index 809dd8a4d..ad8fdcd8e 100644 --- a/docs-master/keybindings/Keybindings_pl.md +++ b/docs-master/keybindings/Keybindings_pl.md @@ -182,7 +182,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` R `` | Zmień nazwę gałęzi | | | `` u `` | Pokaż opcje upstream | Pokaż opcje dotyczące upstream gałęzi, np. ustawianie/usuwanie upstream i resetowanie do upstream. | | `` `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | | -| `` P `` | Push selected branch | Push the selected branch to its upstream branch, after confirming. If no upstream is configured, you will be prompted to configure an upstream branch. | +| `` P `` | Push selected branch | Push the selected branch, after confirming its upstream (pre-filled with what's already configured, or a suggestion if none is). | | `` p `` | Pull selected branch | Pull the selected branch's upstream branch into it, via its linked worktree. If no upstream is configured, you will be prompted to configure an upstream branch. | | `` 0 `` | Focus main view | | | `` `` | Pokaż commity | | diff --git a/docs-master/keybindings/Keybindings_pt.md b/docs-master/keybindings/Keybindings_pt.md index 7ebc3c17a..45177c0f4 100644 --- a/docs-master/keybindings/Keybindings_pt.md +++ b/docs-master/keybindings/Keybindings_pt.md @@ -113,7 +113,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` R `` | Renomear branch | | | `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. | | `` `` | Abrir ferramenta de diff externa (git difftool) | | -| `` P `` | Push selected branch | Push the selected branch to its upstream branch, after confirming. If no upstream is configured, you will be prompted to configure an upstream branch. | +| `` P `` | Push selected branch | Push the selected branch, after confirming its upstream (pre-filled with what's already configured, or a suggestion if none is). | | `` p `` | Pull selected branch | Pull the selected branch's upstream branch into it, via its linked worktree. If no upstream is configured, you will be prompted to configure an upstream branch. | | `` 0 `` | Focar visualização principal | | | `` `` | Ver commits | | diff --git a/docs-master/keybindings/Keybindings_ru.md b/docs-master/keybindings/Keybindings_ru.md index 96455fa07..e983bfd18 100644 --- a/docs-master/keybindings/Keybindings_ru.md +++ b/docs-master/keybindings/Keybindings_ru.md @@ -230,7 +230,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` R `` | Переименовать ветку | | | `` u `` | View upstream options | View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream. | | `` `` | Open external diff tool (git difftool) | | -| `` P `` | Push selected branch | Push the selected branch to its upstream branch, after confirming. If no upstream is configured, you will be prompted to configure an upstream branch. | +| `` P `` | Push selected branch | Push the selected branch, after confirming its upstream (pre-filled with what's already configured, or a suggestion if none is). | | `` p `` | Pull selected branch | Pull the selected branch's upstream branch into it, via its linked worktree. If no upstream is configured, you will be prompted to configure an upstream branch. | | `` 0 `` | Focus main view | | | `` `` | Просмотреть коммиты | | diff --git a/docs-master/keybindings/Keybindings_zh-CN.md b/docs-master/keybindings/Keybindings_zh-CN.md index 10647ec09..e907c6254 100644 --- a/docs-master/keybindings/Keybindings_zh-CN.md +++ b/docs-master/keybindings/Keybindings_zh-CN.md @@ -247,7 +247,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` R `` | 重命名分支 | | | `` u `` | 查看上游选项 | 查看与分支上游相关的选项,例如设置/取消设置上游和重置为上游。 | | `` `` | 使用外部差异比较工具(git difftool) | | -| `` P `` | Push selected branch | Push the selected branch to its upstream branch, after confirming. If no upstream is configured, you will be prompted to configure an upstream branch. | +| `` P `` | Push selected branch | Push the selected branch, after confirming its upstream (pre-filled with what's already configured, or a suggestion if none is). | | `` p `` | Pull selected branch | Pull the selected branch's upstream branch into it, via its linked worktree. If no upstream is configured, you will be prompted to configure an upstream branch. | | `` 0 `` | 聚焦主视图 | | | `` `` | 查看提交 | | diff --git a/docs-master/keybindings/Keybindings_zh-TW.md b/docs-master/keybindings/Keybindings_zh-TW.md index 99018bbea..bf6e5b83a 100644 --- a/docs-master/keybindings/Keybindings_zh-TW.md +++ b/docs-master/keybindings/Keybindings_zh-TW.md @@ -306,7 +306,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct | `` R `` | 重新命名分支 | | | `` u `` | 檢視遠端設定 | 檢視有關遠端分支的設定(例如重設至遠端) | | `` `` | 開啟外部差異工具 (git difftool) | | -| `` P `` | Push selected branch | Push the selected branch to its upstream branch, after confirming. If no upstream is configured, you will be prompted to configure an upstream branch. | +| `` P `` | Push selected branch | Push the selected branch, after confirming its upstream (pre-filled with what's already configured, or a suggestion if none is). | | `` p `` | Pull selected branch | Pull the selected branch's upstream branch into it, via its linked worktree. If no upstream is configured, you will be prompted to configure an upstream branch. | | `` 0 `` | Focus main view | | | `` `` | 檢視提交 | | diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index a58c84615..03184d57b 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -21,7 +21,7 @@ type BranchesController struct { *ListControllerTrait[*models.Branch] c *ControllerCommon - pushBranch func(*models.Branch) error + pushBranch func(branch *models.Branch, upstreamRemote string, upstreamBranch string) error pullBranch func(*models.Branch, *models.Worktree) error } @@ -29,7 +29,7 @@ var _ types.IController = &BranchesController{} func NewBranchesController( c *ControllerCommon, - pushBranch func(*models.Branch) error, + pushBranch func(branch *models.Branch, upstreamRemote string, upstreamBranch string) error, pullBranch func(*models.Branch, *models.Worktree) error, ) *BranchesController { return &BranchesController{ @@ -440,18 +440,14 @@ func (self *BranchesController) press(selectedBranch *models.Branch) error { } func (self *BranchesController) push(branch *models.Branch) error { - self.c.Confirm(types.ConfirmOpts{ - Title: self.c.Tr.PushSelectedBranch, - Prompt: utils.ResolvePlaceholderString( - self.c.Tr.PushSelectedBranchPrompt, - map[string]string{"selectedBranchName": branch.Name}, - ), - HandleConfirm: func() error { - return self.pushBranch(branch) - }, - }) + return self.c.Helpers().Upstream.PromptForUpstreamWithInitialContent(branch, func(upstream string) error { + upstreamRemote, upstreamBranch, err := self.c.Helpers().Upstream.ParseUpstream(upstream) + if err != nil { + return err + } - return nil + return self.pushBranch(branch, upstreamRemote, upstreamBranch) + }) } func (self *BranchesController) pull(branch *models.Branch) error { diff --git a/pkg/gui/controllers/helpers/upstream_helper.go b/pkg/gui/controllers/helpers/upstream_helper.go index 092ca6bb1..1140d5a2f 100644 --- a/pkg/gui/controllers/helpers/upstream_helper.go +++ b/pkg/gui/controllers/helpers/upstream_helper.go @@ -49,8 +49,10 @@ func (self *UpstreamHelper) promptForUpstream(initialContent string, onConfirm f } func (self *UpstreamHelper) PromptForUpstreamWithInitialContent(currentBranch *models.Branch, onConfirm func(string) error) error { - suggestedRemote := self.GetSuggestedRemote() - initialContent := suggestedRemote + " " + currentBranch.Name + initialContent := currentBranch.UpstreamRemote + " " + currentBranch.UpstreamBranch + if !currentBranch.IsTrackingRemote() { + initialContent = self.GetSuggestedRemote() + " " + currentBranch.Name + } return self.promptForUpstream(initialContent, onConfirm) } diff --git a/pkg/gui/controllers/sync_controller.go b/pkg/gui/controllers/sync_controller.go index f6292ea10..5b55d1048 100644 --- a/pkg/gui/controllers/sync_controller.go +++ b/pkg/gui/controllers/sync_controller.go @@ -55,17 +55,32 @@ func (self *SyncController) Context() types.Context { } func (self *SyncController) HandlePush() error { - return self.branchCheckedOut(func(branch *models.Branch) error { - return self.push(branch, false) - })() + return self.branchCheckedOut(self.push)() } -// PushBranch pushes the given branch, regardless of whether it's currently -// checked out. Unlike HandlePush, this always targets the branch explicitly -// (via its own upstream), rather than relying on `git push` implicitly -// pushing whatever is checked out. -func (self *SyncController) PushBranch(branch *models.Branch) error { - return self.push(branch, true) +// PushBranch pushes the given branch to the given upstream, regardless of +// whether the branch is currently checked out. It always names the upstream +// explicitly in the refspec (rather than relying on `git push` implicitly +// targeting whatever is checked out), and (re-)establishes it as the +// branch's tracking upstream. +func (self *SyncController) PushBranch(branch *models.Branch, upstreamRemote string, upstreamBranch string) error { + opts := pushOpts{ + setUpstream: true, + upstreamRemote: upstreamRemote, + upstreamBranch: upstreamBranch, + } + + // If this still targets what's already configured as the branch's + // upstream, we can tell ahead of time whether a force-push will be + // necessary. + if branch.IsTrackingRemote() && branch.UpstreamRemote == upstreamRemote && branch.UpstreamBranch == upstreamBranch { + opts.remoteBranchStoredLocally = branch.RemoteBranchStoredLocally() + if branch.IsBehindForPush() { + return self.requestToForcePush(branch, opts) + } + } + + return self.pushAux(branch, opts) } func (self *SyncController) HandlePull() error { @@ -96,19 +111,10 @@ func (self *SyncController) branchCheckedOut(f func(*models.Branch) error) func( } } -// explicitTarget forces the push to name the branch and its upstream -// explicitly in the refspec, rather than relying on `git push` implicitly -// targeting whatever is currently checked out. This is required whenever -// currentBranch might not be the checked-out branch (e.g. pushing a branch -// selected in the Branches panel). -func (self *SyncController) push(currentBranch *models.Branch, explicitTarget bool) error { +func (self *SyncController) push(currentBranch *models.Branch) error { // if we are behind our upstream branch we'll ask if the user wants to force push if currentBranch.IsTrackingRemote() { opts := pushOpts{remoteBranchStoredLocally: currentBranch.RemoteBranchStoredLocally()} - if explicitTarget { - opts.upstreamRemote = currentBranch.UpstreamRemote - opts.upstreamBranch = currentBranch.UpstreamBranch - } if currentBranch.IsBehindForPush() { return self.requestToForcePush(currentBranch, opts) } @@ -116,7 +122,7 @@ func (self *SyncController) push(currentBranch *models.Branch, explicitTarget bo return self.pushAux(currentBranch, opts) } - if !explicitTarget && self.c.Git().Config.GetPushToCurrent() { + if self.c.Git().Config.GetPushToCurrent() { return self.pushAux(currentBranch, pushOpts{setUpstream: true}) } diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 3a359806a..330ee450c 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -67,7 +67,6 @@ type TranslationSet struct { PullTooltip string PushSelectedBranch string PushSelectedBranchTooltip string - PushSelectedBranchPrompt string PullSelectedBranch string PullSelectedBranchTooltip string PullFailedInOtherWorktree string @@ -1228,8 +1227,7 @@ func EnglishTranslationSet() *TranslationSet { Push: "Push", PushTooltip: "Push the current branch to its upstream branch. If no upstream is configured, you will be prompted to configure an upstream branch.", PushSelectedBranch: "Push selected branch", - PushSelectedBranchTooltip: "Push the selected branch to its upstream branch, after confirming. If no upstream is configured, you will be prompted to configure an upstream branch.", - PushSelectedBranchPrompt: "Push branch '{{.selectedBranchName}}' to its upstream?", + PushSelectedBranchTooltip: "Push the selected branch, after confirming its upstream (pre-filled with what's already configured, or a suggestion if none is).", PullSelectedBranch: "Pull selected branch", PullSelectedBranchTooltip: "Pull the selected branch's upstream branch into it, via its linked worktree. If no upstream is configured, you will be prompted to configure an upstream branch.", PullFailedInOtherWorktree: "Switch to this branch's worktree to resolve the problem.",