Repository: jesseduffield/lazygit (language: go)

Issue:
Is it possible to delete remote tags?
### Discussed in https://github.com/jesseduffield/lazygit/discussions/2633

<div type='discussions-op-text'>

<sup>Originally posted by **AndrewSav** May 17, 2023</sup>
I was able to figure out how to create local tags and push them, but I don't seem to be able to push a deleted local tag. Is this possible?

Also it seems deleting tags locally is futile anyway, they come back from the remote in a minute anyway... Is it possible to make it stick?</div>

P.S. currently achieved through a custom command (eyeballed it):
```
  - key: 'D'
    command: "git push --delete {{ .SelectedTag.FullRefName }}"
    context: 'tags'
    stream: true
    prompts:
      - type: 'confirm'
        title: "Confirm:"
        body: "Are you sure you want to delete the tag {{.SelectedTag}}?"
```


Discussion / hints:
Deleting local tags is only futile if you've already pushed them. What if pressing 'd' brought up a menu that asked if you wanted to delete the local tag, delete the remote tag, or delete both? We could then use that with branches as well. With that approach we're not interfering with muscle memory.
Well the menu thingy sounds nice, had me on "we could then use that with branches as well".

I'd chuck a `good first issue` (?), doesn't seem too wild to add two menus for that.
Agreed
Hey @jesseduffield can I pick this up?
Go for it @AzraelSec !

Fix patch:
diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md
index a0e811f666d..718c2d2be94 100644
--- a/docs/keybindings/Keybindings_en.md
+++ b/docs/keybindings/Keybindings_en.md
@@ -148,7 +148,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
   <kbd>&lt;c-y&gt;</kbd>: Copy pull request URL to clipboard
   <kbd>c</kbd>: Checkout by name
   <kbd>F</kbd>: Force checkout
-  <kbd>d</kbd>: Delete branch
+  <kbd>d</kbd>: View delete options
   <kbd>r</kbd>: Rebase checked-out branch onto this branch
   <kbd>M</kbd>: Merge into currently checked out branch
   <kbd>f</kbd>: Fast-forward this branch from its upstream
@@ -255,7 +255,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
   <kbd>n</kbd>: New branch
   <kbd>M</kbd>: Merge into currently checked out branch
   <kbd>r</kbd>: Rebase checked-out branch onto this branch
-  <kbd>d</kbd>: Delete branch
+  <kbd>d</kbd>: Delete remote tag
   <kbd>u</kbd>: Set as upstream of checked-out branch
   <kbd>g</kbd>: View reset options
   <kbd>w</kbd>: View worktree options
@@ -332,7 +332,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
 
 <pre>
   <kbd>&lt;space&gt;</kbd>: Checkout
-  <kbd>d</kbd>: Delete tag
+  <kbd>d</kbd>: View delete options
   <kbd>P</kbd>: Push tag
   <kbd>n</kbd>: Create tag
   <kbd>g</kbd>: View reset options
diff --git a/docs/keybindings/Keybindings_ja.md b/docs/keybindings/Keybindings_ja.md
index d34463b811e..02e6af23fcf 100644
--- a/docs/keybindings/Keybindings_ja.md
+++ b/docs/keybindings/Keybindings_ja.md
@@ -172,7 +172,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
 
 <pre>
   <kbd>&lt;space&gt;</kbd>: チェックアウト
-  <kbd>d</kbd>: タグを削除
+  <kbd>d</kbd>: View delete options
   <kbd>P</kbd>: タグをpush
   <kbd>n</kbd>: タグを作成
   <kbd>g</kbd>: View reset options
@@ -220,7 +220,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
   <kbd>&lt;c-y&gt;</kbd>: Pull RequestのURLをクリップボードにコピー
   <kbd>c</kbd>: Checkout by name
   <kbd>F</kbd>: Force checkout
-  <kbd>d</kbd>: ブランチを削除
+  <kbd>d</kbd>: View delete options
   <kbd>r</kbd>: Rebase checked-out branch onto this branch
   <kbd>M</kbd>: 現在のブランチにマージ
   <kbd>f</kbd>: Fast-forward this branch from its upstream
@@ -320,7 +320,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
   <kbd>n</kbd>: 新しいブランチを作成
   <kbd>M</kbd>: 現在のブランチにマージ
   <kbd>r</kbd>: Rebase checked-out branch onto this branch
-  <kbd>d</kbd>: ブランチを削除
+  <kbd>d</kbd>: Delete remote tag
   <kbd>u</kbd>: Set as upstream of checked-out branch
   <kbd>g</kbd>: View reset options
   <kbd>w</kbd>: View worktree options
diff --git a/docs/keybindings/Keybindings_ko.md b/docs/keybindings/Keybindings_ko.md
index 5446c24aaf7..4af5fb1a3b6 100644
--- a/docs/keybindings/Keybindings_ko.md
+++ b/docs/keybindings/Keybindings_ko.md
@@ -183,7 +183,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
   <kbd>&lt;c-y&gt;</kbd>: 풀 리퀘스트 URL을 클립보드에 복사
   <kbd>c</kbd>: 이름으로 체크아웃
   <kbd>F</kbd>: 강제 체크아웃
-  <kbd>d</kbd>: 브랜치 삭제
+  <kbd>d</kbd>: View delete options
   <kbd>r</kbd>: 체크아웃된 브랜치를 이 브랜치에 리베이스
   <kbd>M</kbd>: 현재 브랜치에 병합
   <kbd>f</kbd>: Fast-forward this branch from its upstream
@@ -239,7 +239,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
   <kbd>n</kbd>: 새 브랜치 생성
   <kbd>M</kbd>: 현재 브랜치에 병합
   <kbd>r</kbd>: 체크아웃된 브랜치를 이 브랜치에 리베이스
-  <kbd>d</kbd>: 브랜치 삭제
+  <kbd>d</kbd>: Delete remote tag
   <kbd>u</kbd>: Set as upstream of checked-out branch
   <kbd>g</kbd>: View reset options
   <kbd>w</kbd>: View worktree options
@@ -309,7 +309,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
 
 <pre>
   <kbd>&lt;space&gt;</kbd>: 체크아웃
-  <kbd>d</kbd>: 태그 삭제
+  <kbd>d</kbd>: View delete options
   <kbd>P</kbd>: 태그를 push
   <kbd>n</kbd>: 태그를 생성
   <kbd>g</kbd>: View reset options
diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md
index 1593fc56d23..7d366fcdabd 100644
--- a/docs/keybindings/Keybindings_nl.md
+++ b/docs/keybindings/Keybindings_nl.md
@@ -90,7 +90,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
   <kbd>&lt;c-y&gt;</kbd>: Kopieer de URL van het pull-verzoek naar het klembord
   <kbd>c</kbd>: Uitchecken bij naam
   <kbd>F</kbd>: Forceer checkout
-  <kbd>d</kbd>: Verwijder branch
+  <kbd>d</kbd>: View delete options
   <kbd>r</kbd>: Rebase branch
   <kbd>M</kbd>: Merge in met huidige checked out branch
   <kbd>f</kbd>: Fast-forward deze branch vanaf zijn upstream
@@ -233,7 +233,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
   <kbd>n</kbd>: Nieuwe branch
   <kbd>M</kbd>: Merge in met huidige checked out branch
   <kbd>r</kbd>: Rebase branch
-  <kbd>d</kbd>: Verwijder branch
+  <kbd>d</kbd>: Delete remote tag
   <kbd>u</kbd>: Stel in als upstream van uitgecheckte branch
   <kbd>g</kbd>: Bekijk reset opties
   <kbd>w</kbd>: View worktree options
@@ -332,7 +332,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
 
 <pre>
   <kbd>&lt;space&gt;</kbd>: Uitchecken
-  <kbd>d</kbd>: Verwijder tag
+  <kbd>d</kbd>: View delete options
   <kbd>P</kbd>: Push tag
   <kbd>n</kbd>: Creëer tag
   <kbd>g</kbd>: Bekijk reset opties
diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md
index 01a7a621c20..f4f59228efb 100644
--- a/docs/keybindings/Keybindings_pl.md
+++ b/docs/keybindings/Keybindings_pl.md
@@ -106,7 +106,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
   <kbd>&lt;c-y&gt;</kbd>: Skopiuj adres URL żądania pobrania do schowka
   <kbd>c</kbd>: Przełącz używając nazwy
   <kbd>F</kbd>: Wymuś przełączenie
-  <kbd>d</kbd>: Usuń gałąź
+  <kbd>d</kbd>: View delete options
   <kbd>r</kbd>: Zmiana bazy gałęzi
   <kbd>M</kbd>: Scal do obecnej gałęzi
   <kbd>f</kbd>: Fast-forward this branch from its upstream
@@ -232,7 +232,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
   <kbd>n</kbd>: Nowa gałąź
   <kbd>M</kbd>: Scal do obecnej gałęzi
   <kbd>r</kbd>: Zmiana bazy gałęzi
-  <kbd>d</kbd>: Usuń gałąź
+  <kbd>d</kbd>: Delete remote tag
   <kbd>u</kbd>: Set as upstream of checked-out branch
   <kbd>g</kbd>: Wyświetl opcje resetu
   <kbd>w</kbd>: View worktree options
@@ -325,7 +325,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
 
 <pre>
   <kbd>&lt;space&gt;</kbd>: Przełącz
-  <kbd>d</kbd>: Delete tag
+  <kbd>d</kbd>: View delete options
   <kbd>P</kbd>: Push tag
   <kbd>n</kbd>: Create tag
   <kbd>g</kbd>: Wyświetl opcje resetu
diff --git a/docs/keybindings/Keybindings_ru.md b/docs/keybindings/Keybindings_ru.md
index 6ae627bc9ab..9a03d2935a6 100644
--- a/docs/keybindings/Keybindings_ru.md
+++ b/docs/keybindings/Keybindings_ru.md
@@ -181,7 +181,7 @@ _Связки клавиш_
   <kbd>&lt;c-y&gt;</kbd>: Скопировать URL запроса на принятие изменений в буфер обмена
   <kbd>c</kbd>: Переключить по названию
   <kbd>F</kbd>: Принудительное переключение
-  <kbd>d</kbd>: Удалить ветку
+  <kbd>d</kbd>: View delete options
   <kbd>r</kbd>: Перебазировать переключённую ветку на эту ветку
   <kbd>M</kbd>: Слияние с текущей переключённой веткой
   <kbd>f</kbd>: Перемотать эту ветку вперёд из её upstream-ветки
@@ -277,7 +277,7 @@ _Связки клавиш_
 
 <pre>
   <kbd>&lt;space&gt;</kbd>: Переключить
-  <kbd>d</kbd>: Удалить тег
+  <kbd>d</kbd>: View delete options
   <kbd>P</kbd>: Отправить тег
   <kbd>n</kbd>: Создать тег
   <kbd>g</kbd>: Просмотреть параметры сброса
@@ -294,7 +294,7 @@ _Связки клавиш_
   <kbd>n</kbd>: Новая ветка
   <kbd>M</kbd>: Слияние с текущей переключённой веткой
   <kbd>r</kbd>: Перебазировать переключённую ветку на эту ветку
-  <kbd>d</kbd>: Удалить ветку
+  <kbd>d</kbd>: Delete remote tag
   <kbd>u</kbd>: Установить как upstream-ветку переключённую ветку
   <kbd>g</kbd>: Просмотреть параметры сброса
   <kbd>w</kbd>: View worktree options
diff --git a/docs/keybindings/Keybindings_zh-CN.md b/docs/keybindings/Keybindings_zh-CN.md
index 924607639ef..6f60cb644c1 100644
--- a/docs/keybindings/Keybindings_zh-CN.md
+++ b/docs/keybindings/Keybindings_zh-CN.md
@@ -84,7 +84,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
   <kbd>&lt;c-y&gt;</kbd>: 将抓取请求 URL 复制到剪贴板
   <kbd>c</kbd>: 按名称检出
   <kbd>F</kbd>: 强制检出
-  <kbd>d</kbd>: 删除分支
+  <kbd>d</kbd>: View delete options
   <kbd>r</kbd>: 将已检出的分支变基到该分支
   <kbd>M</kbd>: 合并到当前检出的分支
   <kbd>f</kbd>: 从上游快进此分支
@@ -234,7 +234,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
 
 <pre>
   <kbd>&lt;space&gt;</kbd>: 检出
-  <kbd>d</kbd>: 删除标签
+  <kbd>d</kbd>: View delete options
   <kbd>P</kbd>: 推送标签
   <kbd>n</kbd>: 创建标签
   <kbd>g</kbd>: 查看重置选项
@@ -334,7 +334,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
   <kbd>n</kbd>: 新分支
   <kbd>M</kbd>: 合并到当前检出的分支
   <kbd>r</kbd>: 将已检出的分支变基到该分支
-  <kbd>d</kbd>: 删除分支
+  <kbd>d</kbd>: Delete remote tag
   <kbd>u</kbd>: 设置为检出分支的上游
   <kbd>g</kbd>: 查看重置选项
   <kbd>w</kbd>: View worktree options
diff --git a/docs/keybindings/Keybindings_zh-TW.md b/docs/keybindings/Keybindings_zh-TW.md
index 4103a88ecbf..eb82367b539 100644
--- a/docs/keybindings/Keybindings_zh-TW.md
+++ b/docs/keybindings/Keybindings_zh-TW.md
@@ -256,7 +256,7 @@ _說明：`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B，`B`表示 Shift+B_
   <kbd>&lt;c-y&gt;</kbd>: 複製拉取請求的 URL 到剪貼板
   <kbd>c</kbd>: 根據名稱檢出
   <kbd>F</kbd>: 強制檢出
-  <kbd>d</kbd>: 刪除分支
+  <kbd>d</kbd>: View delete options
   <kbd>r</kbd>: 將已檢出的分支變基至此分支
   <kbd>M</kbd>: 合併到當前檢出的分支
   <kbd>f</kbd>: 從上游快進此分支
@@ -273,7 +273,7 @@ _說明：`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B，`B`表示 Shift+B_
 
 <pre>
   <kbd>&lt;space&gt;</kbd>: 檢出
-  <kbd>d</kbd>: 刪除標籤
+  <kbd>d</kbd>: View delete options
   <kbd>P</kbd>: 推送標籤
   <kbd>n</kbd>: 建立標籤
   <kbd>g</kbd>: 檢視重設選項
@@ -344,7 +344,7 @@ _說明：`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B，`B`表示 Shift+B_
   <kbd>n</kbd>: 新分支
   <kbd>M</kbd>: 合併到當前檢出的分支
   <kbd>r</kbd>: 將已檢出的分支變基至此分支
-  <kbd>d</kbd>: 刪除分支
+  <kbd>d</kbd>: Delete remote tag
   <kbd>u</kbd>: 將此分支設為當前分支之上游
   <kbd>g</kbd>: 檢視重設選項
   <kbd>w</kbd>: View worktree options
diff --git a/pkg/commands/git_commands/branch.go b/pkg/commands/git_commands/branch.go
index 24244080bda..b8d562dae9f 100644
--- a/pkg/commands/git_commands/branch.go
+++ b/pkg/commands/git_commands/branch.go
@@ -85,8 +85,8 @@ func (self *BranchCommands) CurrentBranchName() (string, error) {
 	return "", err
 }
 
-// Delete delete branch
-func (self *BranchCommands) Delete(branch string, force bool) error {
+// LocalDelete delete branch locally
+func (self *BranchCommands) LocalDelete(branch string, force bool) error {
 	cmdArgs := NewGitCmd("branch").
 		ArgIfElse(force, "-D", "-d").
 		Arg(branch).
diff --git a/pkg/commands/git_commands/remote.go b/pkg/commands/git_commands/remote.go
index b9f20fb3a07..ce8f7944244 100644
--- a/pkg/commands/git_commands/remote.go
+++ b/pkg/commands/git_commands/remote.go
@@ -56,6 +56,14 @@ func (self *RemoteCommands) DeleteRemoteBranch(task gocui.Task, remoteName strin
 	return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
 }
 
+func (self *RemoteCommands) DeleteRemoteTag(task gocui.Task, remoteName string, tagName string) error {
+	cmdArgs := NewGitCmd("push").
+		Arg(remoteName, "--delete", tagName).
+		ToArgv()
+
+	return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run()
+}
+
 // CheckRemoteBranchExists Returns remote branch
 func (self *RemoteCommands) CheckRemoteBranchExists(branchName string) bool {
 	cmdArgs := NewGitCmd("show-ref").
diff --git a/pkg/commands/git_commands/tag.go b/pkg/commands/git_commands/tag.go
index 2517ce380be..0656e1e19a3 100644
--- a/pkg/commands/git_commands/tag.go
+++ b/pkg/commands/git_commands/tag.go
@@ -41,7 +41,7 @@ func (self *TagCommands) HasTag(tagName string) bool {
 	return self.cmd.New(cmdArgs).Run() == nil
 }
 
-func (self *TagCommands) Delete(tagName string) error {
+func (self *TagCommands) LocalDelete(tagName string) error {
 	cmdArgs := NewGitCmd("tag").Arg("-d", tagName).
 		ToArgv()
 
diff --git a/pkg/gui/controllers.go b/pkg/gui/controllers.go
index cc45d833a9e..1430ad239e4 100644
--- a/pkg/gui/controllers.go
+++ b/pkg/gui/controllers.go
@@ -86,6 +86,7 @@ func (gui *Gui) resetHelpersAndControllers() {
 		Files:           helpers.NewFilesHelper(helperCommon),
 		WorkingTree:     helpers.NewWorkingTreeHelper(helperCommon, refsHelper, commitsHelper, gpgHelper),
 		Tags:            helpers.NewTagsHelper(helperCommon, commitsHelper),
+		BranchesHelper:  helpers.NewBranchesHelper(helperCommon),
 		GPG:             helpers.NewGpgHelper(helperCommon),
 		MergeAndRebase:  rebaseHelper,
 		MergeConflicts:  mergeConflictsHelper,
diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go
index e7023959f83..84d9e838e27 100644
--- a/pkg/gui/controllers/branches_controller.go
+++ b/pkg/gui/controllers/branches_controller.go
@@ -70,7 +70,8 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty
 		{
 			Key:         opts.GetKey(opts.Config.Universal.Remove),
 			Handler:     self.checkSelectedAndReal(self.delete),
-			Description: self.c.Tr.DeleteBranch,
+			Description: self.c.Tr.ViewDeleteOptions,
+			OpensMenu:   true,
 		},
 		{
 			Key:         opts.GetKey(opts.Config.Branches.RebaseBranch),
@@ -316,19 +317,6 @@ func (self *BranchesController) createNewBranchWithName(newBranchName string) er
 	return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
 }
 
-func (self *BranchesController) delete(branch *models.Branch) error {
-	checkedOutBranch := self.c.Helpers().Refs.GetCheckedOutRef()
-	if checkedOutBranch.Name == branch.Name {
-		return self.c.ErrorMsg(self.c.Tr.CantDeleteCheckOutBranch)
-	}
-
-	if self.checkedOutByOtherWorktree(branch) {
-		return self.promptWorktreeBranchDelete(branch)
-	}
-
-	return self.deleteWithForce(branch, false)
-}
-
 func (self *BranchesController) checkedOutByOtherWorktree(branch *models.Branch) bool {
 	return git_commands.CheckedOutByOtherWorktree(branch, self.c.Model().Worktrees)
 }
@@ -371,18 +359,34 @@ func (self *BranchesController) promptWorktreeBranchDelete(selectedBranch *model
 	})
 }
 
-func (self *BranchesController) deleteWithForce(selectedBranch *models.Branch, force bool) error {
-	title := self.c.Tr.DeleteBranch
-	var templateStr string
-	if force {
-		templateStr = self.c.Tr.ForceDeleteBranchMessage
-	} else {
-		templateStr = self.c.Tr.DeleteBranchMessage
+func (self *BranchesController) localDelete(branch *models.Branch) error {
+	if self.checkedOutByOtherWorktree(branch) {
+		return self.promptWorktreeBranchDelete(branch)
 	}
+
+	return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(_ gocui.Task) error {
+		self.c.LogAction(self.c.Tr.Actions.DeleteLocalBranch)
+		err := self.c.Git().Branch.LocalDelete(branch.Name, false)
+		if err != nil && strings.Contains(err.Error(), "git branch -D ") {
+			return self.forceDelete(branch)
+		}
+		if err != nil {
+			return self.c.Error(err)
+		}
+		return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
+	})
+}
+
+func (self *BranchesController) remoteDelete(branch *models.Branch) error {
+	return self.c.Helpers().BranchesHelper.ConfirmDeleteRemote(branch.UpstreamRemote, branch.Name)
+}
+
+func (self *BranchesController) forceDelete(branch *models.Branch) error {
+	title := self.c.Tr.ForceDeleteBranchTitle
 	message := utils.ResolvePlaceholderString(
-		templateStr,
+		self.c.Tr.ForceDeleteBranchMessage,
 		map[string]string{
-			"selectedBranchName": selectedBranch.Name,
+			"selectedBranchName": branch.Name,
 		},
 	)
 
@@ -390,19 +394,60 @@ func (self *BranchesController) deleteWithForce(selectedBranch *models.Branch, f
 		Title:  title,
 		Prompt: message,
 		HandleConfirm: func() error {
-			self.c.LogAction(self.c.Tr.Actions.DeleteBranch)
-			if err := self.c.Git().Branch.Delete(selectedBranch.Name, force); err != nil {
-				errMessage := err.Error()
-				if !force && strings.Contains(errMessage, "git branch -D ") {
-					return self.deleteWithForce(selectedBranch, true)
-				}
-				return self.c.ErrorMsg(errMessage)
+			if err := self.c.Git().Branch.LocalDelete(branch.Name, true); err != nil {
+				return self.c.ErrorMsg(err.Error())
 			}
 			return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}})
 		},
 	})
 }
 
+func (self *BranchesController) delete(branch *models.Branch) error {
+	menuItems := []*types.MenuItem{}
+	checkedOutBranch := self.c.Helpers().Refs.GetCheckedOutRef()
+
+	localDeleteItem := &types.MenuItem{
+		Label: self.c.Tr.DeleteLocalBranch,
+		Key:   'c',
+		OnPress: func() error {
+			return self.localDelete(branch)
+		},
+	}
+	if checkedOutBranch.Name == branch.Name {
+		localDeleteItem = &types.MenuItem{
+			Label:   self.c.Tr.DeleteLocalBranch,
+			Key:     'c',
+			Tooltip: self.c.Tr.CantDeleteCheckOutBranch,
+			OnPress: func() error {
+				return self.c.ErrorMsg(self.c.Tr.CantDeleteCheckOutBranch)
+			},
+		}
+	}
+	menuItems = append(menuItems, localDeleteItem)
+
+	if branch.IsTrackingRemote() && !branch.UpstreamGone {
+		menuItems = append(menuItems, &types.MenuItem{
+			Label: self.c.Tr.DeleteRemoteBranch,
+			Key:   'r',
+			OnPress: func() error {
+				return self.remoteDelete(branch)
+			},
+		})
+	}
+
+	menuTitle := utils.ResolvePlaceholderString(
+		self.c.Tr.DeleteBranchTitle,
+		map[string]string{
+			"selectedBranchName": branch.Name,
+		},
+	)
+
+	return self.c.Menu(types.CreateMenuOptions{
+		Title: menuTitle,
+		Items: menuItems,
+	})
+}
+
 func (self *BranchesController) merge() error {
 	selectedBranchName := self.context().GetSelected().Name
 	return self.c.Helpers().MergeAndRebase.MergeRefIntoCheckedOutBranch(selectedBranchName)
diff --git a/pkg/gui/controllers/helpers/branches_helper.go b/pkg/gui/controllers/helpers/branches_helper.go
new file mode 100644
index 00000000000..6bc336e8e76
--- /dev/null
+++ b/pkg/gui/controllers/helpers/branches_helper.go
@@ -0,0 +1,46 @@
+package helpers
+
+import (
+	"github.com/jesseduffield/gocui"
+	"github.com/jesseduffield/lazygit/pkg/gui/types"
+	"github.com/jesseduffield/lazygit/pkg/utils"
+)
+
+type BranchesHelper struct {
+	c *HelperCommon
+}
+
+func NewBranchesHelper(c *HelperCommon) *BranchesHelper {
+	return &BranchesHelper{
+		c: c,
+	}
+}
+
+func (self *BranchesHelper) ConfirmDeleteRemote(remoteName string, branchName string) error {
+	title := utils.ResolvePlaceholderString(
+		self.c.Tr.DeleteBranchTitle,
+		map[string]string{
+			"selectedBranchName": branchName,
+		},
+	)
+	prompt := utils.ResolvePlaceholderString(
+		self.c.Tr.DeleteRemoteBranchPrompt,
+		map[string]string{
+			"selectedBranchName": branchName,
+			"upstream":           remoteName,
+		},
+	)
+	return self.c.Confirm(types.ConfirmOpts{
+		Title:  title,
+		Prompt: prompt,
+		HandleConfirm: func() error {
+			return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(task gocui.Task) error {
+				self.c.LogAction(self.c.Tr.Actions.DeleteRemoteBranch)
+				if err := self.c.Git().Remote.DeleteRemoteBranch(task, remoteName, branchName); err != nil {
+					return self.c.Error(err)
+				}
+				return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
+			})
+		},
+	})
+}
diff --git a/pkg/gui/controllers/helpers/helpers.go b/pkg/gui/controllers/helpers/helpers.go
index e87b57eb060..22a7ea91bf1 100644
--- a/pkg/gui/controllers/helpers/helpers.go
+++ b/pkg/gui/controllers/helpers/helpers.go
@@ -22,6 +22,7 @@ type Helpers struct {
 	Suggestions    *SuggestionsHelper
 	Files          *FilesHelper
 	WorkingTree    *WorkingTreeHelper
+	BranchesHelper *BranchesHelper
 	Tags           *TagsHelper
 	MergeAndRebase *MergeAndRebaseHelper
 	MergeConflicts *MergeConflictsHelper
diff --git a/pkg/gui/controllers/remote_branches_controller.go b/pkg/gui/controllers/remote_branches_controller.go
index 529b00a906d..ffb55d5cad2 100644
--- a/pkg/gui/controllers/remote_branches_controller.go
+++ b/pkg/gui/controllers/remote_branches_controller.go
@@ -1,10 +1,8 @@
 package controllers
 
 import (
-	"fmt"
 	"strings"
 
-	"github.com/jesseduffield/gocui"
 	"github.com/jesseduffield/lazygit/pkg/commands/models"
 	"github.com/jesseduffield/lazygit/pkg/gui/context"
 	"github.com/jesseduffield/lazygit/pkg/gui/types"
@@ -53,7 +51,7 @@ func (self *RemoteBranchesController) GetKeybindings(opts types.KeybindingsOpts)
 		{
 			Key:         opts.GetKey(opts.Config.Universal.Remove),
 			Handler:     self.checkSelected(self.delete),
-			Description: self.c.Tr.DeleteBranch,
+			Description: self.c.Tr.DeleteRemoteTag,
 		},
 		{
 			Key:         opts.GetKey(opts.Config.Branches.SetUpstream),
@@ -112,23 +110,7 @@ func (self *RemoteBranchesController) checkSelected(callback func(*models.Remote
 }
 
 func (self *RemoteBranchesController) delete(selectedBranch *models.RemoteBranch) error {
-	message := fmt.Sprintf("%s '%s'?", self.c.Tr.DeleteRemoteBranchMessage, selectedBranch.FullName())
-
-	return self.c.Confirm(types.ConfirmOpts{
-		Title:  self.c.Tr.DeleteRemoteBranch,
-		Prompt: message,
-		HandleConfirm: func() error {
-			return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(task gocui.Task) error {
-				self.c.LogAction(self.c.Tr.Actions.DeleteRemoteBranch)
-				err := self.c.Git().Remote.DeleteRemoteBranch(task, selectedBranch.RemoteName, selectedBranch.Name)
-				if err != nil {
-					_ = self.c.Error(err)
-				}
-
-				return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.REMOTES}})
-			})
-		},
-	})
+	return self.c.Helpers().BranchesHelper.ConfirmDeleteRemote(selectedBranch.RemoteName, selectedBranch.Name)
 }
 
 func (self *RemoteBranchesController) merge(selectedBranch *models.RemoteBranch) error {
diff --git a/pkg/gui/controllers/tags_controller.go b/pkg/gui/controllers/tags_controller.go
index 80248391ed0..91d590c3204 100644
--- a/pkg/gui/controllers/tags_controller.go
+++ b/pkg/gui/controllers/tags_controller.go
@@ -34,7 +34,8 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types.
 		{
 			Key:         opts.GetKey(opts.Config.Universal.Remove),
 			Handler:     self.withSelectedTag(self.delete),
-			Description: self.c.Tr.DeleteTag,
+			Description: self.c.Tr.ViewDeleteOptions,
+			OpensMenu:   true,
 		},
 		{
 			Key:         opts.GetKey(opts.Config.Branches.PushTag),
@@ -88,24 +89,90 @@ func (self *TagsController) checkout(tag *models.Tag) error {
 	return self.c.PushContext(self.c.Contexts().Branches)
 }
 
+func (self *TagsController) localDelete(tag *models.Tag) error {
+	return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(gocui.Task) error {
+		self.c.LogAction(self.c.Tr.Actions.DeleteLocalTag)
+		if err := self.c.Git().Tag.LocalDelete(tag.Name); err != nil {
+			return self.c.Error(err)
+		}
+		return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}})
+	})
+}
+
+func (self *TagsController) remoteDelete(tag *models.Tag) error {
+	title := utils.ResolvePlaceholderString(
+		self.c.Tr.SelectRemoteTagUpstream,
+		map[string]string{
+			"tagName": tag.Name,
+		},
+	)
+
+	return self.c.Prompt(types.PromptOpts{
+		Title:               title,
+		InitialContent:      "origin",
+		FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRemoteSuggestionsFunc(),
+		HandleConfirm: func(upstream string) error {
+			confirmTitle := utils.ResolvePlaceholderString(
+				self.c.Tr.DeleteTagTitle,
+				map[string]string{
+					"tagName": tag.Name,
+				},
+			)
+			confirmPrompt := utils.ResolvePlaceholderString(
+				self.c.Tr.DeleteRemoteTagPrompt,
+				map[string]string{
+					"tagName":  tag.Name,
+					"upstream": upstream,
+				},
+			)
+
+			return self.c.Confirm(types.ConfirmOpts{
+				Title:  confirmTitle,
+				Prompt: confirmPrompt,
+				HandleConfirm: func() error {
+					return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(t gocui.Task) error {
+						self.c.LogAction(self.c.Tr.Actions.DeleteRemoteTag)
+						if err := self.c.Git().Remote.DeleteRemoteTag(t, upstream, tag.Name); err != nil {
+							return self.c.Error(err)
+						}
+						self.c.Toast(self.c.Tr.RemoteTagDeletedMessage)
+						return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}})
+					})
+				},
+			})
+		},
+	})
+}
+
 func (self *TagsController) delete(tag *models.Tag) error {
-	prompt := utils.ResolvePlaceholderString(
-		self.c.Tr.DeleteTagPrompt,
+	menuTitle := utils.ResolvePlaceholderString(
+		self.c.Tr.DeleteTagTitle,
 		map[string]string{
 			"tagName": tag.Name,
 		},
 	)
 
-	return self.c.Confirm(types.ConfirmOpts{
-		Title:  self.c.Tr.DeleteTagTitle,
-		Prompt: prompt,
-		HandleConfirm: func() error {
-			self.c.LogAction(self.c.Tr.Actions.DeleteTag)
-			if err := self.c.Git().Tag.Delete(tag.Name); err != nil {
-				return self.c.Error(err)
-			}
-			return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}})
+	menuItems := []*types.MenuItem{
+		{
+			Label: self.c.Tr.DeleteLocalTag,
+			Key:   'c',
+			OnPress: func() error {
+				return self.localDelete(tag)
+			},
 		},
+		{
+			Label:     self.c.Tr.DeleteRemoteTag,
+			Key:       'r',
+			OpensMenu: true,
+			OnPress: func() error {
+				return self.remoteDelete(tag)
+			},
+		},
+	}
+
+	return self.c.Menu(types.CreateMenuOptions{
+		Title: menuTitle,
+		Items: menuItems,
 	})
 }
 
diff --git a/pkg/i18n/chinese.go b/pkg/i18n/chinese.go
index 2a494c97efd..b7ec74811d6 100644
--- a/pkg/i18n/chinese.go
+++ b/pkg/i18n/chinese.go
@@ -82,8 +82,6 @@ func chineseTranslationSet() TranslationSet {
 		BranchName:                          "分支名称",
 		NewBranchNameBranchOff:              "新分支名称（基于 {{.branchName}}）",
 		CantDeleteCheckOutBranch:            "您不能删除已检出的分支！",
-		DeleteBranch:                        "删除分支",
-		DeleteBranchMessage:                 "您确定要删除分支 {{.selectedBranchName}} 吗？",
 		ForceDeleteBranchMessage:            "{{.selectedBranchName}} 还没有被完全合并。您确定要删除它吗？",
 		RebaseBranch:                        "将已检出的分支变基到该分支",
 		CantRebaseOntoSelf:                  "您不能将分支变基到其自身",
@@ -309,9 +307,6 @@ func chineseTranslationSet() TranslationSet {
 		TagMessageTitle:                     "标签消息",
 		AnnotatedTag:                        "附注标签",
 		LightweightTag:                      "轻量标签",
-		DeleteTag:                           "删除标签",
-		DeleteTagTitle:                      "删除标签",
-		DeleteTagPrompt:                     "您确定要删除标签 {{.tagName}} 吗？",
 		PushTagTitle:                        "将 {{.tagName}} 推送到远程仓库：",
 		PushTag:                             "推送标签",
 		CreateTag:                           "创建标签",
@@ -457,7 +452,6 @@ func chineseTranslationSet() TranslationSet {
 			CheckoutTag:                       "检出标签",
 			CheckoutBranch:                    "检出分支",
 			ForceCheckoutBranch:               "强制检出分支",
-			DeleteBranch:                      "删除分支",
 			Merge:                             "合并",
 			RebaseBranch:                      "变基分支",
 			RenameBranch:                      "重命名分支",
@@ -521,7 +515,6 @@ func chineseTranslationSet() TranslationSet {
 			BulkUpdateSubmodules:              "批量更新子模块",
 			BulkDeinitialiseSubmodules:        "批量取消初始化子模块",
 			UpdateSubmodule:                   "更新子模块",
-			DeleteTag:                         "删除标签",
 			PushTag:                           "推送标签",
 			NukeWorkingTree:                   "Nuke 工作树",
 			DiscardUnstagedFileChanges:        "放弃未暂存的文件更改",
diff --git a/pkg/i18n/dutch.go b/pkg/i18n/dutch.go
index 79e1f89ecb6..284a81b6060 100644
--- a/pkg/i18n/dutch.go
+++ b/pkg/i18n/dutch.go
@@ -48,8 +48,6 @@ func dutchTranslationSet() TranslationSet {
 		BranchName:                          "Branch naam",
 		NewBranchNameBranchOff:              "Nieuw branch naam (Branch is afgeleid van '{{.branchName}}')",
 		CantDeleteCheckOutBranch:            "Je kan een uitgecheckte branch niet verwijderen!",
-		DeleteBranch:                        "Verwijder branch",
-		DeleteBranchMessage:                 "Weet je zeker dat je branch '{{.selectedBranchName}}' wilt verwijderen?",
 		ForceDeleteBranchMessage:            "Weet je zeker dat je branch '{{.selectedBranchName}}' geforceerd wil verwijderen?",
 		RebaseBranch:                        "Rebase branch",
 		CantRebaseOntoSelf:                  "Je kan niet een branch rebasen op zichzelf",
@@ -263,10 +261,7 @@ func dutchTranslationSet() TranslationSet {
 		SetUpstreamMessage:                  "Weet je zeker dat je de upstream branch van '{{.checkedOut}}' naar '{{.selected}}' wilt zetten",
 		EditRemote:                          "Wijzig remote",
 		TagCommit:                           "Tag commit",
-		TagNameTitle:                        "Tag naam",
-		DeleteTag:                           "Verwijder tag",
-		DeleteTagTitle:                      "Verwijder tag",
-		DeleteTagPrompt:                     "Weet je zeker dat je '{{.tagName}}' wil verwijderen?",
+		TagNameTitle:                        "Tag naam:",
 		PushTagTitle:                        "Remote om tag '{{.tagName}}' te pushen naar:",
 		PushTag:                             "Push tag",
 		CreateTag:                           "Creëer tag",
diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go
index 6dee0046766..cc8106e603f 100644
--- a/pkg/i18n/english.go
+++ b/pkg/i18n/english.go
@@ -68,8 +68,11 @@ type TranslationSet struct {
 	BranchName                          string
 	NewBranchNameBranchOff              string
 	CantDeleteCheckOutBranch            string
-	DeleteBranch                        string
-	DeleteBranchMessage                 string
+	DeleteBranchTitle                   string
+	DeleteLocalBranch                   string
+	DeleteRemoteBranchOption            string
+	DeleteRemoteBranchPrompt            string
+	ForceDeleteBranchTitle              string
 	ForceDeleteBranchMessage            string
 	RebaseBranch                        string
 	CantRebaseOntoSelf                  string
@@ -292,6 +295,7 @@ type TranslationSet struct {
 	DiscardUntrackedFiles               string
 	DiscardStagedChanges                string
 	HardReset                           string
+	ViewDeleteOptions                   string
 	ViewResetOptions                    string
 	CreateFixupCommit                   string
 	CreateFixupCommitDescription        string
@@ -352,9 +356,12 @@ type TranslationSet struct {
 	TagMessageTitle                     string
 	LightweightTag                      string
 	AnnotatedTag                        string
-	DeleteTag                           string
 	DeleteTagTitle                      string
-	DeleteTagPrompt                     string
+	DeleteLocalTag                      string
+	DeleteRemoteTag                     string
+	SelectRemoteTagUpstream             string
+	DeleteRemoteTagPrompt               string
+	RemoteTagDeletedMessage             string
 	PushTagTitle                        string
 	PushTag                             string
 	CreateTag                           string
@@ -632,6 +639,7 @@ type Actions struct {
 	CheckoutTag                       string
 	CheckoutBranch                    string
 	ForceCheckoutBranch               string
+	DeleteLocalBranch                 string
 	DeleteBranch                      string
 	Merge                             string
 	RebaseBranch                      string
@@ -714,7 +722,8 @@ type Actions struct {
 	UpdateSubmodule                   string
 	CreateLightweightTag              string
 	CreateAnnotatedTag                string
-	DeleteTag                         string
+	DeleteLocalTag                    string
+	DeleteRemoteTag                   string
 	PushTag                           string
 	NukeWorkingTree                   string
 	DiscardUnstagedFileChanges        string
@@ -828,8 +837,11 @@ func EnglishTranslationSet() TranslationSet {
 		BranchName:                          "Branch name",
 		NewBranchNameBranchOff:              "New branch name (branch is off of '{{.branchName}}')",
 		CantDeleteCheckOutBranch:            "You cannot delete the checked out branch!",
-		DeleteBranch:                        "Delete branch",
-		DeleteBranchMessage:                 "Are you sure you want to delete the branch '{{.selectedBranchName}}'?",
+		DeleteBranchTitle:                   "Delete branch '{{.selectedBranchName}}'?",
+		DeleteLocalBranch:                   "Delete local branch",
+		DeleteRemoteBranchOption:            "Delete remote branch",
+		DeleteRemoteBranchPrompt:            "Are you sure you want to delete the remote branch '{{.selectedBranchName}}' from '{{.upstream}}'?",
+		ForceDeleteBranchTitle:              "Force delete branch",
 		ForceDeleteBranchMessage:            "'{{.selectedBranchName}}' is not fully merged. Are you sure you want to delete it?",
 		RebaseBranch:                        "Rebase checked-out branch onto this branch",
 		CantRebaseOntoSelf:                  "You cannot rebase a branch onto itself",
@@ -1055,6 +1067,7 @@ func EnglishTranslationSet() TranslationSet {
 		DiscardUntrackedFiles:               "Discard untracked files",
 		DiscardStagedChanges:                "Discard staged changes",
 		HardReset:                           "Hard reset",
+		ViewDeleteOptions:                   "View delete options",
 		ViewResetOptions:                    `View reset options`,
 		CreateFixupCommitDescription:        `Create fixup commit for this commit`,
 		SquashAboveCommits:                  `Squash all 'fixup!' commits above selected commit (autosquash)`,
@@ -1101,7 +1114,7 @@ func EnglishTranslationSet() TranslationSet {
 		EditRemoteUrl:                       `Enter updated remote url for {{.remoteName}}:`,
 		RemoveRemote:                        `Remove remote`,
 		RemoveRemotePrompt:                  "Are you sure you want to remove remote",
-		DeleteRemoteBranch:                  "Delete Remote Branch",
+		DeleteRemoteBranch:                  "Delete remote branch",
 		DeleteRemoteBranchMessage:           "Are you sure you want to delete remote branch",
 		SetAsUpstream:                       "Set as upstream of checked-out branch",
 		SetUpstream:                         "Set upstream of selected branch",
@@ -1115,9 +1128,12 @@ func EnglishTranslationSet() TranslationSet {
 		TagMessageTitle:                     "Tag description",
 		AnnotatedTag:                        "Annotated tag",
 		LightweightTag:                      "Lightweight tag",
-		DeleteTag:                           "Delete tag",
-		DeleteTagTitle:                      "Delete tag",
-		DeleteTagPrompt:                     "Are you sure you want to delete tag '{{.tagName}}'?",
+		DeleteTagTitle:                      "Delete tag '{{.tagName}}'?",
+		DeleteLocalTag:                      "Delete local tag",
+		DeleteRemoteTag:                     "Delete remote tag",
+		RemoteTagDeletedMessage:             "Remote tag deleted",
+		SelectRemoteTagUpstream:             "Remote from which to remove tag '{{.tagName}}':",
+		DeleteRemoteTagPrompt:               "Are you sure you want to delete the remote tag '{{.tagName}}' from '{{.upstream}}'?",
 		PushTagTitle:                        "Remote to push tag '{{.tagName}}' to:",
 		PushTag:                             "Push tag",
 		CreateTag:                           "Create tag",
@@ -1353,6 +1369,7 @@ func EnglishTranslationSet() TranslationSet {
 			CheckoutTag:                       "Checkout tag",
 			CheckoutBranch:                    "Checkout branch",
 			ForceCheckoutBranch:               "Force checkout branch",
+			DeleteLocalBranch:                 "Delete local branch",
 			DeleteBranch:                      "Delete branch",
 			Merge:                             "Merge",
 			RebaseBranch:                      "Rebase branch",
@@ -1434,7 +1451,8 @@ func EnglishTranslationSet() TranslationSet {
 			BulkUpdateSubmodules:              "Bulk update submodules",
 			BulkDeinitialiseSubmodules:        "Bulk deinitialise submodules",
 			UpdateSubmodule:                   "Update submodule",
-			DeleteTag:                         "Delete tag",
+			DeleteLocalTag:                    "Delete local tag",
+			DeleteRemoteTag:                   "Delete remote tag",
 			PushTag:                           "Push tag",
 			NukeWorkingTree:                   "Nuke working tree",
 			DiscardUnstagedFileChanges:        "Discard unstaged file changes",
diff --git a/pkg/i18n/japanese.go b/pkg/i18n/japanese.go
index 3cbc6e225ae..1b8c530654f 100644
--- a/pkg/i18n/japanese.go
+++ b/pkg/i18n/japanese.go
@@ -73,9 +73,6 @@ func japaneseTranslationSet() TranslationSet {
 		BranchName:               "ブランチ名",
 		NewBranchNameBranchOff:   "新規ブランチ名 ('{{.branchName}}' に作成)",
 		CantDeleteCheckOutBranch: "チェックアウト中のブランチは削除できません!",
-		DeleteBranch:             "ブランチを削除",
-		DeleteBranchMessage:      "ブランチ '{{.selectedBranchName}}' を削除します。よろしいですか?",
-		ForceDeleteBranchMessage: "'{{.selectedBranchName}}' はマージされていません。本当に削除しますか?",
 		// LcRebaseBranch:                      "Rebase checked-out branch onto this branch",
 		CantRebaseOntoSelf:        "ブランチを自分自身にリベースすることはできません。",
 		CantMergeBranchIntoItself: "ブランチを自分自身にマージすることはできません。",
@@ -319,9 +316,6 @@ func japaneseTranslationSet() TranslationSet {
 		TagMessageTitle:        "タグメッセージ",
 		AnnotatedTag:           "注釈付きタグ",
 		LightweightTag:         "軽量タグ",
-		DeleteTag:              "タグを削除",
-		DeleteTagTitle:         "タグを削除",
-		DeleteTagPrompt:        "タグ '{{.tagName}}' を削除します。よろしいですか?",
 		PushTagTitle:           "リモートにタグ '{{.tagName}}' をpush",
 		PushTag:                "タグをpush",
 		CreateTag:              "タグを作成",
@@ -554,7 +548,6 @@ func japaneseTranslationSet() TranslationSet {
 			BulkUpdateSubmodules:              "サブモジュールを一括更新",
 			// BulkDeinitialiseSubmodules:        "Bulk deinitialise submodules",
 			UpdateSubmodule: "サブモジュールを更新",
-			DeleteTag:       "タグを削除",
 			PushTag:         "タグをpush",
 			// NukeWorkingTree:                   "Nuke working tree",
 			// DiscardUnstagedFileChanges:        "Discard unstaged file changes",
diff --git a/pkg/i18n/korean.go b/pkg/i18n/korean.go
index f22e6cc4728..32c29db14e2 100644
--- a/pkg/i18n/korean.go
+++ b/pkg/i18n/korean.go
@@ -72,8 +72,6 @@ func koreanTranslationSet() TranslationSet {
 		BranchName:                          "브랜치 이름",
 		NewBranchNameBranchOff:              "새 브랜치 이름 (branch is off of '{{.branchName}}')",
 		CantDeleteCheckOutBranch:            "체크아웃하는 브랜치는 삭제할 수 없습니다!",
-		DeleteBranch:                        "브랜치 삭제",
-		DeleteBranchMessage:                 "정말로 브랜치 '{{.selectedBranchName}}' 를 삭제하시겠습니까?",
 		ForceDeleteBranchMessage:            "'{{.selectedBranchName}}'는 완전히 병합되지 않았습니다. 정말 삭제하시겠습니까?",
 		RebaseBranch:                        "체크아웃된 브랜치를 이 브랜치에 리베이스",
 		CantRebaseOntoSelf:                  "브랜치를 자기 자신에게 리베이스할 수는 없습니다.",
@@ -314,9 +312,6 @@ func koreanTranslationSet() TranslationSet {
 		TagMessageTitle:            "태그 메시지",
 		AnnotatedTag:               "Annotated tag",
 		LightweightTag:             "Lightweight tag",
-		DeleteTag:                  "태그 삭제",
-		DeleteTagTitle:             "태그 삭제",
-		DeleteTagPrompt:            "정말로 태그 '{{.tagName}}' 를 삭제하시겠습니까?",
 		PushTagTitle:               "원격에 태그 '{{.tagName}}' 를 푸시",
 		PushTag:                    "태그를 push",
 		CreateTag:                  "태그를 생성",
@@ -478,7 +473,6 @@ func koreanTranslationSet() TranslationSet {
 			CheckoutTag:                       "태그 체크아웃",
 			CheckoutBranch:                    "브랜치 체크아웃",
 			ForceCheckoutBranch:               "브랜치 Force 체크아웃",
-			DeleteBranch:                      "브랜치 삭제",
 			Merge:                             "병합",
 			RebaseBranch:                      "브랜치 리베이스",
 			RenameBranch:                      "브랜치 이름 변경",
@@ -552,7 +546,6 @@ func koreanTranslationSet() TranslationSet {
 			BulkUpdateSubmodules:              "Bulk update submodules",
 			BulkDeinitialiseSubmodules:        "Bulk deinitialise submodules",
 			UpdateSubmodule:                   "서브모듈 업데이트",
-			DeleteTag:                         "태그 삭제",
 			PushTag:                           "태그 푸시g",
 			NukeWorkingTree:                   "Nuke working tree",
 			DiscardUnstagedFileChanges:        "Unstaged 파일 변경사항 버리기",
diff --git a/pkg/i18n/polish.go b/pkg/i18n/polish.go
index a2ff1bb1278..5ec7b95484e 100644
--- a/pkg/i18n/polish.go
+++ b/pkg/i18n/polish.go
@@ -43,8 +43,6 @@ func polishTranslationSet() TranslationSet {
 		BranchName:                          "Nazwa gałęzi",
 		NewBranchNameBranchOff:              "Nazwa nowej gałęzi (gałąź na bazie '{{.branchName}}')",
 		CantDeleteCheckOutBranch:            "Nie możesz usunąć obecnie przełączonej gałęzi!",
-		DeleteBranch:                        "Usuń gałąź",
-		DeleteBranchMessage:                 "Jesteś pewien, że chcesz usunąć gałąź '{{.selectedBranchName}}' ?",
 		ForceDeleteBranchMessage:            "Na pewno wymusić usunięcie gałęzi '{{.selectedBranchName}}'?",
 		RebaseBranch:                        "Zmiana bazy gałęzi",
 		CantRebaseOntoSelf:                  "Nie możesz zmienić bazy gałęzi na nią samą",
diff --git a/pkg/i18n/russian.go b/pkg/i18n/russian.go
index ae21430e6b8..fc8806e7386 100644
--- a/pkg/i18n/russian.go
+++ b/pkg/i18n/russian.go
@@ -91,8 +91,6 @@ func RussianTranslationSet() TranslationSet {
 		BranchName:                          "Название ветки",
 		NewBranchNameBranchOff:              "Название новой ветки (Ветка с '{{.branchName}}')",
 		CantDeleteCheckOutBranch:            "Невозможно удалить переключённую ветку!",
-		DeleteBranch:                        "Удалить ветку",
-		DeleteBranchMessage:                 "Вы уверены, что хотите удалить ветку '{{.selectedBranchName}}'?",
 		ForceDeleteBranchMessage:            "'{{.selectedBranchName}}' не полностью слилась. Вы уверены, что хотите удалить его?",
 		RebaseBranch:                        "Перебазировать переключённую ветку на эту ветку",
 		CantRebaseOntoSelf:                  "Невозможно перебазировать ветку на себя",
@@ -375,9 +373,7 @@ func RussianTranslationSet() TranslationSet {
 		TagMessageTitle:                     "Сообщения тега",
 		AnnotatedTag:                        "Аннотированный тег",
 		LightweightTag:                      "Легковесный тег",
-		DeleteTag:                           "Удалить тег",
 		DeleteTagTitle:                      "Удалить тег",
-		DeleteTagPrompt:                     "Вы уверены, что хотите удалить тег '{{.tagName}}'?",
 		PushTagTitle:                        "Удалённый репозитории для отправки тега '{{.tagName}}' в:",
 		PushTag:                             "Отправить тег",
 		CreateTag:                           "Создать тег",
@@ -647,7 +643,6 @@ func RussianTranslationSet() TranslationSet {
 			BulkUpdateSubmodules:              "Массовое обновление подмодулей",
 			BulkDeinitialiseSubmodules:        "Массовая деинициализация подмодулей",
 			UpdateSubmodule:                   "Обновить подмодуль",
-			DeleteTag:                         "Удалить тег",
 			PushTag:                           "Отправить тег",
 			NukeWorkingTree:                   "Уничтожить рабочее дерево",
 			DiscardUnstagedFileChanges:        "Отменить непроиндексированные изменения файла",
diff --git a/pkg/i18n/traditional_chinese.go b/pkg/i18n/traditional_chinese.go
index 3ccac945a4e..8c5dc959958 100644
--- a/pkg/i18n/traditional_chinese.go
+++ b/pkg/i18n/traditional_chinese.go
@@ -124,8 +124,6 @@ func traditionalChineseTranslationSet() TranslationSet {
 		BranchName:                          "分支名稱",
 		NewBranchNameBranchOff:              "新的分支名稱 (根據 '{{.branchName}}' 分支創建)",
 		CantDeleteCheckOutBranch:            "你不能刪除已檢出的分支！",
-		DeleteBranch:                        "刪除分支",
-		DeleteBranchMessage:                 "你確定要刪除 '{{.selectedBranchName}}' 分支嗎？",
 		ForceDeleteBranchMessage:            "'{{.selectedBranchName}}' 分支尚未完全合併。你確定要刪除嗎？",
 		RebaseBranch:                        "將已檢出的分支變基至此分支",
 		CantRebaseOntoSelf:                  "你不能將分支變基至自己",
@@ -402,9 +400,6 @@ func traditionalChineseTranslationSet() TranslationSet {
 		TagMessageTitle:                     "標籤訊息",
 		AnnotatedTag:                        "附註標籤",
 		LightweightTag:                      "輕量標籤",
-		DeleteTag:                           "刪除標籤",
-		DeleteTagTitle:                      "刪除標籤",
-		DeleteTagPrompt:                     "你確定要刪除 '{{.tagName}}' 標籤嗎？",
 		PushTagTitle:                        "推送標籤 '{{.tagName}}' 至遠端：",
 		PushTag:                             "推送標籤",
 		CreateTag:                           "建立標籤",
@@ -674,7 +669,6 @@ func traditionalChineseTranslationSet() TranslationSet {
 			BulkUpdateSubmodules:              "批量更新子模塊",
 			BulkDeinitialiseSubmodules:        "批量取消初始化子模塊",
 			UpdateSubmodule:                   "更新子模塊",
-			DeleteTag:                         "刪除標籤",
 			PushTag:                           "推送標籤",
 			NukeWorkingTree:                   "清空工作樹",
 			DiscardUnstagedFileChanges:        "放棄未預存的檔案更改",
diff --git a/pkg/integration/components/git.go b/pkg/integration/components/git.go
index f11c3342cfe..ed327b3ede2 100644
--- a/pkg/integration/components/git.go
+++ b/pkg/integration/components/git.go
@@ -18,14 +18,28 @@ func (self *Git) TagNamesAt(ref string, expectedNames []string) *Git {
 	return self.assert([]string{"git", "tag", "--sort=v:refname", "--points-at", ref}, strings.Join(expectedNames, "\n"))
 }
 
+func (self *Git) RemoteTagDeleted(ref string, tagName string) *Git {
+	return self.expect([]string{"git", "ls-remote", ref, fmt.Sprintf("refs/tags/%s", tagName)}, func(s string) (bool, string) {
+		return len(s) == 0, fmt.Sprintf("Expected tag %s to have been removed from %s", tagName, ref)
+	})
+}
+
 func (self *Git) assert(cmdArgs []string, expected string) *Git {
+	self.expect(cmdArgs, func(output string) (bool, string) {
+		return output == expected, fmt.Sprintf("Expected current branch name to be '%s', but got '%s'", expected, output)
+	})
+
+	return self
+}
+
+func (self *Git) expect(cmdArgs []string, condition func(string) (bool, string)) *Git {
 	self.assertWithRetries(func() (bool, string) {
 		output, err := self.shell.runCommandWithOutput(cmdArgs)
 		if err != nil {
 			return false, fmt.Sprintf("Unexpected error running command: `%v`. Error: %s", cmdArgs, err.Error())
 		}
 		actual := strings.TrimSpace(output)
-		return actual == expected, fmt.Sprintf("Expected current branch name to be '%s', but got '%s'", expected, actual)
+		return condition(actual)
 	})
 
 	return self
diff --git a/pkg/integration/components/menu_driver.go b/pkg/integration/components/menu_driver.go
index 34d081dfade..7ab42a3e1c8 100644
--- a/pkg/integration/components/menu_driver.go
+++ b/pkg/integration/components/menu_driver.go
@@ -66,6 +66,12 @@ func (self *MenuDriver) Wait(milliseconds int) *MenuDriver {
 	return self
 }
 
+func (self *MenuDriver) Tooltip(option *TextMatcher) *MenuDriver {
+	self.t.Views().Tooltip().Content(option)
+
+	return self
+}
+
 func (self *MenuDriver) checkNecessaryChecksCompleted() {
 	if !self.hasCheckedTitle {
 		self.t.Fail("You must check the title of a menu popup by calling Title() before calling Confirm()/Cancel().")
diff --git a/pkg/integration/components/shell.go b/pkg/integration/components/shell.go
index 7b0e9ddbfb6..4ba1bff679f 100644
--- a/pkg/integration/components/shell.go
+++ b/pkg/integration/components/shell.go
@@ -162,6 +162,10 @@ func (self *Shell) CreateAnnotatedTag(name string, message string, ref string) *
 	return self.RunCommand([]string{"git", "tag", "-a", name, "-m", message, ref})
 }
 
+func (self *Shell) PushBranch(upstream, branch string) *Shell {
+	return self.RunCommand([]string{"git", "push", "--set-upstream", upstream, branch})
+}
+
 // convenience method for creating a file and adding it
 func (self *Shell) CreateFileAndAdd(fileName string, fileContents string) *Shell {
 	return self.
diff --git a/pkg/integration/components/views.go b/pkg/integration/components/views.go
index eb4f585dcd6..c7655da749c 100644
--- a/pkg/integration/components/views.go
+++ b/pkg/integration/components/views.go
@@ -222,3 +222,7 @@ func (self *Views) Suggestions() *ViewDriver {
 func (self *Views) Search() *ViewDriver {
 	return self.regularView("search")
 }
+
+func (self *Views) Tooltip() *ViewDriver {
+	return self.regularView("tooltip")
+}


Test patch:
diff --git a/pkg/commands/git_commands/branch_test.go b/pkg/commands/git_commands/branch_test.go
index dee2b03c89a..b94f700ccac 100644
--- a/pkg/commands/git_commands/branch_test.go
+++ b/pkg/commands/git_commands/branch_test.go
@@ -93,7 +93,7 @@ func TestBranchDeleteBranch(t *testing.T) {
 		t.Run(s.testName, func(t *testing.T) {
 			instance := buildBranchCommands(commonDeps{runner: s.runner})
 
-			s.test(instance.Delete("test", s.force))
+			s.test(instance.LocalDelete("test", s.force))
 			s.runner.CheckForMissingCalls()
 		})
 	}
diff --git a/pkg/integration/tests/branch/delete.go b/pkg/integration/tests/branch/delete.go
index 78c21f7a7d1..cdda78ec6a1 100644
--- a/pkg/integration/tests/branch/delete.go
+++ b/pkg/integration/tests/branch/delete.go
@@ -6,38 +6,110 @@ import (
 )
 
 var Delete = NewIntegrationTest(NewIntegrationTestArgs{
-	Description:  "Try to delete the checked out branch first (to no avail), and then delete another branch.",
+	Description:  "Try all combination of local and remote branch deletions",
 	ExtraCmdArgs: []string{},
 	Skip:         false,
 	SetupConfig:  func(config *config.AppConfig) {},
 	SetupRepo: func(shell *Shell) {
 		shell.
+			CloneIntoRemote("origin").
 			EmptyCommit("blah").
 			NewBranch("branch-one").
-			NewBranch("branch-two")
+			PushBranch("origin", "branch-one").
+			NewBranch("branch-two").
+			PushBranch("origin", "branch-two").
+			EmptyCommit("deletion blocker").
+			NewBranch("branch-three")
 	},
 	Run: func(t *TestDriver, keys config.KeybindingConfig) {
 		t.Views().Branches().
 			Focus().
 			Lines(
-				MatchesRegexp(`\*.*branch-two`).IsSelected(),
+				MatchesRegexp(`\*.*branch-three`).IsSelected(),
+				MatchesRegexp(`branch-two`),
 				MatchesRegexp(`branch-one`),
 				MatchesRegexp(`master`),
 			).
 			Press(keys.Universal.Remove).
 			Tap(func() {
-				t.ExpectPopup().Alert().Title(Equals("Error")).Content(Contains("You cannot delete the checked out branch!")).Confirm()
+				t.ExpectPopup().
+					Menu().
+					Tooltip(Contains("You cannot delete the checked out branch!")).
+					Title(Equals("Delete branch 'branch-three'?")).
+					Select(Contains("Delete local branch")).
+					Confirm()
+				t.ExpectPopup().
+					Alert().
+					Title(Equals("Error")).
+					Content(Contains("You cannot delete the checked out branch!")).
+					Confirm()
 			}).
 			SelectNextItem().
 			Press(keys.Universal.Remove).
 			Tap(func() {
-				t.ExpectPopup().Confirmation().
-					Title(Equals("Delete branch")).
-					Content(Contains("Are you sure you want to delete the branch 'branch-one'?")).
+				t.ExpectPopup().
+					Menu().
+					Title(Equals("Delete branch 'branch-two'?")).
+					Select(Contains("Delete local branch")).
+					Confirm()
+			}).
+			Tap(func() {
+				t.ExpectPopup().
+					Confirmation().
+					Title(Equals("Force delete branch")).
+					Content(Equals("'branch-two' is not fully merged. Are you sure you want to delete it?")).
+					Confirm()
+			}).
+			Lines(
+				MatchesRegexp(`\*.*branch-three`),
+				MatchesRegexp(`branch-one`).IsSelected(),
+				MatchesRegexp(`master`),
+			).
+			Press(keys.Universal.Remove).
+			Tap(func() {
+				t.ExpectPopup().
+					Menu().
+					Title(Equals("Delete branch 'branch-one'?")).
+					Select(Contains("Delete remote branch")).
+					Confirm()
+			}).
+			Tap(func() {
+				t.ExpectPopup().
+					Confirmation().
+					Title(Equals("Delete branch 'branch-one'?")).
+					Content(Equals("Are you sure you want to delete the remote branch 'branch-one' from 'origin'?")).
+					Confirm()
+			}).
+			Tap(func() {
+				t.Views().Remotes().
+					Focus().
+					Lines(Contains("origin")).
+					PressEnter()
+
+				t.Views().
+					RemoteBranches().
+					Lines(Equals("branch-two")).
+					Press(keys.Universal.Return)
+
+				t.Views().
+					Branches().
+					Focus()
+			}).
+			Lines(
+				MatchesRegexp(`\*.*branch-three`),
+				MatchesRegexp(`branch-one \(upstream gone\)`).IsSelected(),
+				MatchesRegexp(`master`),
+			).
+			Press(keys.Universal.Remove).
+			Tap(func() {
+				t.ExpectPopup().
+					Menu().
+					Title(Equals("Delete branch 'branch-one'?")).
+					Select(Contains("Delete local branch")).
 					Confirm()
 			}).
 			Lines(
-				MatchesRegexp(`\*.*branch-two`),
+				MatchesRegexp(`\*.*branch-three`),
 				MatchesRegexp(`master`).IsSelected(),
 			)
 	},
diff --git a/pkg/integration/tests/tag/crud_annotated.go b/pkg/integration/tests/tag/crud_annotated.go
index d32c7f26559..930859c902c 100644
--- a/pkg/integration/tests/tag/crud_annotated.go
+++ b/pkg/integration/tests/tag/crud_annotated.go
@@ -12,6 +12,7 @@ var CrudAnnotated = NewIntegrationTest(NewIntegrationTestArgs{
 	SetupConfig:  func(config *config.AppConfig) {},
 	SetupRepo: func(shell *Shell) {
 		shell.EmptyCommit("initial commit")
+		shell.CloneIntoRemote("origin")
 	},
 	Run: func(t *TestDriver, keys config.KeybindingConfig) {
 		t.Views().Tags().
@@ -31,11 +32,53 @@ var CrudAnnotated = NewIntegrationTest(NewIntegrationTestArgs{
 			Lines(
 				MatchesRegexp(`new-tag.*message`).IsSelected(),
 			).
+			Press(keys.Universal.Push).
+			Tap(func() {
+				t.ExpectPopup().Prompt().
+					Title(Equals("Remote to push tag 'new-tag' to:")).
+					InitialText(Equals("origin")).
+					SuggestionLines(
+						Contains("origin"),
+					).
+					Confirm()
+			}).
+			Press(keys.Universal.Remove).
+			Tap(func() {
+				t.ExpectPopup().
+					Menu().
+					Title(Equals("Delete tag 'new-tag'?")).
+					Select(Contains("Delete remote tag")).
+					Confirm()
+			}).
+			Tap(func() {
+				t.ExpectPopup().Prompt().
+					Title(Equals("Remote from which to remove tag 'new-tag':")).
+					InitialText(Equals("origin")).
+					SuggestionLines(
+						Contains("origin"),
+					).
+					Confirm()
+			}).
+			Tap(func() {
+				t.ExpectPopup().
+					Confirmation().
+					Title(Equals("Delete tag 'new-tag'?")).
+					Content(Equals("Are you sure you want to delete the remote tag 'new-tag' from 'origin'?")).
+					Confirm()
+			}).
+			Lines(
+				MatchesRegexp(`new-tag.*message`).IsSelected(),
+			).
+			Tap(func() {
+				t.Git().
+					RemoteTagDeleted("origin", "new-tag")
+			}).
 			Press(keys.Universal.Remove).
 			Tap(func() {
-				t.ExpectPopup().Confirmation().
-					Title(Equals("Delete tag")).
-					Content(Equals("Are you sure you want to delete tag 'new-tag'?")).
+				t.ExpectPopup().
+					Menu().
+					Title(Equals("Delete tag 'new-tag'?")).
+					Select(Contains("Delete local tag")).
 					Confirm()
 			}).
 			IsEmpty().
diff --git a/pkg/integration/tests/tag/crud_lightweight.go b/pkg/integration/tests/tag/crud_lightweight.go
index ce5ff9e42e4..6aab10dd183 100644
--- a/pkg/integration/tests/tag/crud_lightweight.go
+++ b/pkg/integration/tests/tag/crud_lightweight.go
@@ -12,6 +12,7 @@ var CrudLightweight = NewIntegrationTest(NewIntegrationTestArgs{
 	SetupConfig:  func(config *config.AppConfig) {},
 	SetupRepo: func(shell *Shell) {
 		shell.EmptyCommit("initial commit")
+		shell.CloneIntoRemote("origin")
 	},
 	Run: func(t *TestDriver, keys config.KeybindingConfig) {
 		t.Views().Tags().
@@ -36,11 +37,53 @@ var CrudLightweight = NewIntegrationTest(NewIntegrationTestArgs{
 					).
 					PressEscape()
 			}).
+			Press(keys.Universal.Push).
+			Tap(func() {
+				t.ExpectPopup().Prompt().
+					Title(Equals("Remote to push tag 'new-tag' to:")).
+					InitialText(Equals("origin")).
+					SuggestionLines(
+						Contains("origin"),
+					).
+					Confirm()
+			}).
+			Press(keys.Universal.Remove).
+			Tap(func() {
+				t.ExpectPopup().
+					Menu().
+					Title(Equals("Delete tag 'new-tag'?")).
+					Select(Contains("Delete remote tag")).
+					Confirm()
+			}).
+			Tap(func() {
+				t.ExpectPopup().Prompt().
+					Title(Equals("Remote from which to remove tag 'new-tag':")).
+					InitialText(Equals("origin")).
+					SuggestionLines(
+						Contains("origin"),
+					).
+					Confirm()
+			}).
+			Tap(func() {
+				t.ExpectPopup().
+					Confirmation().
+					Title(Equals("Delete tag 'new-tag'?")).
+					Content(Equals("Are you sure you want to delete the remote tag 'new-tag' from 'origin'?")).
+					Confirm()
+			}).
+			Lines(
+				MatchesRegexp(`new-tag.*initial commit`).IsSelected(),
+			).
+			Tap(func() {
+				t.Git().
+					RemoteTagDeleted("origin", "new-tag")
+			}).
 			Press(keys.Universal.Remove).
 			Tap(func() {
-				t.ExpectPopup().Confirmation().
-					Title(Equals("Delete tag")).
-					Content(Equals("Are you sure you want to delete tag 'new-tag'?")).
+				t.ExpectPopup().
+					Menu().
+					Title(Equals("Delete tag 'new-tag'?")).
+					Select(Contains("Delete local tag")).
 					Confirm()
 			}).
 			IsEmpty()
diff --git a/pkg/integration/tests/worktree/detach_worktree_from_branch.go b/pkg/integration/tests/worktree/detach_worktree_from_branch.go
index 09b3146e5aa..f6724ef3a8e 100644
--- a/pkg/integration/tests/worktree/detach_worktree_from_branch.go
+++ b/pkg/integration/tests/worktree/detach_worktree_from_branch.go
@@ -27,6 +27,13 @@ var DetachWorktreeFromBranch = NewIntegrationTest(NewIntegrationTestArgs{
 			).
 			NavigateToLine(Contains("newbranch")).
 			Press(keys.Universal.Remove).
+			Tap(func() {
+				t.ExpectPopup().
+					Menu().
+					Title(Equals("Delete branch 'newbranch'?")).
+					Select(Contains("Delete local branch")).
+					Confirm()
+			}).
 			Tap(func() {
 				t.ExpectPopup().Menu().
 					Title(Equals("Branch newbranch is checked out by worktree linked-worktree")).
diff --git a/pkg/integration/tests/worktree/remove_worktree_from_branch.go b/pkg/integration/tests/worktree/remove_worktree_from_branch.go
index 2885f5669f8..7ef9d0ae9f7 100644
--- a/pkg/integration/tests/worktree/remove_worktree_from_branch.go
+++ b/pkg/integration/tests/worktree/remove_worktree_from_branch.go
@@ -28,6 +28,13 @@ var RemoveWorktreeFromBranch = NewIntegrationTest(NewIntegrationTestArgs{
 			).
 			NavigateToLine(Contains("newbranch")).
 			Press(keys.Universal.Remove).
+			Tap(func() {
+				t.ExpectPopup().
+					Menu().
+					Title(Equals("Delete branch 'newbranch'?")).
+					Select(Contains("Delete local branch")).
+					Confirm()
+			}).
 			Tap(func() {
 				t.ExpectPopup().Menu().
 					Title(Equals("Branch newbranch is checked out by worktree linked-worktree")).