mirror of
				https://github.com/jesseduffield/lazygit.git
				synced 2025-10-30 23:57:43 +02:00 
			
		
		
		
	Allow deleting remote tags/branches from local tag/branch views (#2738)
This commit is contained in:
		| @@ -148,7 +148,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_ | ||||
|   <kbd><c-y></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><space></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 | ||||
|   | ||||
| @@ -172,7 +172,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_ | ||||
|  | ||||
| <pre> | ||||
|   <kbd><space></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><c-y></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 | ||||
|   | ||||
| @@ -183,7 +183,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_ | ||||
|   <kbd><c-y></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><space></kbd>: 체크아웃 | ||||
|   <kbd>d</kbd>: 태그 삭제 | ||||
|   <kbd>d</kbd>: View delete options | ||||
|   <kbd>P</kbd>: 태그를 push | ||||
|   <kbd>n</kbd>: 태그를 생성 | ||||
|   <kbd>g</kbd>: View reset options | ||||
|   | ||||
| @@ -90,7 +90,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_ | ||||
|   <kbd><c-y></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><space></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 | ||||
|   | ||||
| @@ -106,7 +106,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_ | ||||
|   <kbd><c-y></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><space></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 | ||||
|   | ||||
| @@ -181,7 +181,7 @@ _Связки клавиш_ | ||||
|   <kbd><c-y></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><space></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 | ||||
|   | ||||
| @@ -84,7 +84,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_ | ||||
|   <kbd><c-y></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><space></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 | ||||
|   | ||||
| @@ -256,7 +256,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_ | ||||
|   <kbd><c-y></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><space></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 | ||||
|   | ||||
| @@ -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). | ||||
|   | ||||
| @@ -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() | ||||
| 		}) | ||||
| 	} | ||||
|   | ||||
| @@ -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"). | ||||
|   | ||||
| @@ -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() | ||||
|  | ||||
|   | ||||
| @@ -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, | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
							
								
								
									
										46
									
								
								pkg/gui/controllers/helpers/branches_helper.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								pkg/gui/controllers/helpers/branches_helper.go
									
									
									
									
									
										Normal file
									
								
							| @@ -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}}) | ||||
| 			}) | ||||
| 		}, | ||||
| 	}) | ||||
| } | ||||
| @@ -22,6 +22,7 @@ type Helpers struct { | ||||
| 	Suggestions    *SuggestionsHelper | ||||
| 	Files          *FilesHelper | ||||
| 	WorkingTree    *WorkingTreeHelper | ||||
| 	BranchesHelper *BranchesHelper | ||||
| 	Tags           *TagsHelper | ||||
| 	MergeAndRebase *MergeAndRebaseHelper | ||||
| 	MergeConflicts *MergeConflictsHelper | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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,27 +89,93 @@ func (self *TagsController) checkout(tag *models.Tag) error { | ||||
| 	return self.c.PushContext(self.c.Contexts().Branches) | ||||
| } | ||||
|  | ||||
| func (self *TagsController) delete(tag *models.Tag) error { | ||||
| 	prompt := utils.ResolvePlaceholderString( | ||||
| 		self.c.Tr.DeleteTagPrompt, | ||||
| 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.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}}) | ||||
| 	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 { | ||||
| 	menuTitle := utils.ResolvePlaceholderString( | ||||
| 		self.c.Tr.DeleteTagTitle, | ||||
| 		map[string]string{ | ||||
| 			"tagName": tag.Name, | ||||
| 		}, | ||||
| 	) | ||||
|  | ||||
| 	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, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| func (self *TagsController) push(tag *models.Tag) error { | ||||
| 	title := utils.ResolvePlaceholderString( | ||||
| 		self.c.Tr.PushTagTitle, | ||||
|   | ||||
| @@ -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:        "放弃未暂存的文件更改", | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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 | ||||
| @@ -633,6 +640,7 @@ type Actions struct { | ||||
| 	CheckoutTag                       string | ||||
| 	CheckoutBranch                    string | ||||
| 	ForceCheckoutBranch               string | ||||
| 	DeleteLocalBranch                 string | ||||
| 	DeleteBranch                      string | ||||
| 	Merge                             string | ||||
| 	RebaseBranch                      string | ||||
| @@ -715,7 +723,8 @@ type Actions struct { | ||||
| 	UpdateSubmodule                   string | ||||
| 	CreateLightweightTag              string | ||||
| 	CreateAnnotatedTag                string | ||||
| 	DeleteTag                         string | ||||
| 	DeleteLocalTag                    string | ||||
| 	DeleteRemoteTag                   string | ||||
| 	PushTag                           string | ||||
| 	NukeWorkingTree                   string | ||||
| 	DiscardUnstagedFileChanges        string | ||||
| @@ -829,8 +838,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", | ||||
| @@ -1056,6 +1068,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)`, | ||||
| @@ -1102,7 +1115,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", | ||||
| @@ -1116,9 +1129,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", | ||||
| @@ -1355,6 +1371,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", | ||||
| @@ -1436,7 +1453,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", | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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 파일 변경사항 버리기", | ||||
|   | ||||
| @@ -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ą", | ||||
|   | ||||
| @@ -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:        "Отменить непроиндексированные изменения файла", | ||||
|   | ||||
| @@ -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:        "放棄未預存的檔案更改", | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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().") | ||||
|   | ||||
| @@ -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. | ||||
|   | ||||
| @@ -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") | ||||
| } | ||||
|   | ||||
| @@ -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-two`), | ||||
| 				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-three`), | ||||
| 				MatchesRegexp(`master`).IsSelected(), | ||||
| 			) | ||||
| 	}, | ||||
|   | ||||
| @@ -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().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 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(). | ||||
| 					Menu(). | ||||
| 					Title(Equals("Delete tag 'new-tag'?")). | ||||
| 					Select(Contains("Delete local tag")). | ||||
| 					Confirm() | ||||
| 			}). | ||||
| 			IsEmpty(). | ||||
|   | ||||
| @@ -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().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 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(). | ||||
| 					Menu(). | ||||
| 					Title(Equals("Delete tag 'new-tag'?")). | ||||
| 					Select(Contains("Delete local tag")). | ||||
| 					Confirm() | ||||
| 			}). | ||||
| 			IsEmpty() | ||||
|   | ||||
| @@ -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")). | ||||
|   | ||||
| @@ -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")). | ||||
|   | ||||
		Reference in New Issue
	
	Block a user