Always prompt for the upstream when pushing the selected branch (#4)

* Revert "Always confirm before pushing the selected branch (#3)"

This reverts commit 619bbf71c7.

* 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 <khanh_t@arbin.com>
This commit is contained in:
Trương Duy Khánh 2026-08-10 11:08:48 +07:00 committed by GitHub
parent 619bbf71c7
commit 158029dbf2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 49 additions and 47 deletions

View file

@ -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. |
| `` <ctrl+t> `` | 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 | |
| `` <enter> `` | View commits | |

View file

@ -396,7 +396,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| `` R `` | ブランチ名を変更 | |
| `` u `` | アップストリームオプションを表示 | ブランチのアップストリームに関連するオプションを表示します(例:アップストリームの設定/解除やアップストリームへのリセット)。 |
| `` <ctrl+t> `` | 外部差分ツールを開く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 `` | メインビューにフォーカス | |
| `` <enter> `` | コミットを表示 | |

View file

@ -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. |
| `` <ctrl+t> `` | 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 | |
| `` <enter> `` | 커밋 보기 | |

View file

@ -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. |
| `` <ctrl+t> `` | 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 | |
| `` <enter> `` | Bekijk commits | |

View file

@ -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. |
| `` <ctrl+t> `` | 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 | |
| `` <enter> `` | Pokaż commity | |

View file

@ -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. |
| `` <ctrl+t> `` | 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 | |
| `` <enter> `` | Ver commits | |

View file

@ -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. |
| `` <ctrl+t> `` | 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 | |
| `` <enter> `` | Просмотреть коммиты | |

View file

@ -247,7 +247,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| `` R `` | 重命名分支 | |
| `` u `` | 查看上游选项 | 查看与分支上游相关的选项,例如设置/取消设置上游和重置为上游。 |
| `` <ctrl+t> `` | 使用外部差异比较工具(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 `` | 聚焦主视图 | |
| `` <enter> `` | 查看提交 | |

View file

@ -306,7 +306,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| `` R `` | 重新命名分支 | |
| `` u `` | 檢視遠端設定 | 檢視有關遠端分支的設定(例如重設至遠端) |
| `` <ctrl+t> `` | 開啟外部差異工具 (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 | |
| `` <enter> `` | 檢視提交 | |

View file

@ -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 {

View file

@ -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)
}

View file

@ -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})
}

View file

@ -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.",