1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-02-09 13:47:11 +02:00

Allow deleting remote tags/branches from local tag/branch views (#2738)

This commit is contained in:
Federico 2023-08-10 09:39:26 +02:00 committed by GitHub
parent c43830b027
commit 0df5cb1286
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 487 additions and 158 deletions

View File

@ -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>&lt;c-y&gt;</kbd>: Copy pull request URL to clipboard
<kbd>c</kbd>: Checkout by name <kbd>c</kbd>: Checkout by name
<kbd>F</kbd>: Force checkout <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>r</kbd>: Rebase checked-out branch onto this branch
<kbd>M</kbd>: Merge into currently checked out branch <kbd>M</kbd>: Merge into currently checked out branch
<kbd>f</kbd>: Fast-forward this branch from its upstream <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>n</kbd>: New branch
<kbd>M</kbd>: Merge into currently checked out branch <kbd>M</kbd>: Merge into currently checked out branch
<kbd>r</kbd>: Rebase checked-out branch onto this 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>u</kbd>: Set as upstream of checked-out branch
<kbd>g</kbd>: View reset options <kbd>g</kbd>: View reset options
<kbd>w</kbd>: View worktree 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> <pre>
<kbd>&lt;space&gt;</kbd>: Checkout <kbd>&lt;space&gt;</kbd>: Checkout
<kbd>d</kbd>: Delete tag <kbd>d</kbd>: View delete options
<kbd>P</kbd>: Push tag <kbd>P</kbd>: Push tag
<kbd>n</kbd>: Create tag <kbd>n</kbd>: Create tag
<kbd>g</kbd>: View reset options <kbd>g</kbd>: View reset options

View File

@ -172,7 +172,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
<pre> <pre>
<kbd>&lt;space&gt;</kbd>: チェックアウト <kbd>&lt;space&gt;</kbd>: チェックアウト
<kbd>d</kbd>: タグを削除 <kbd>d</kbd>: View delete options
<kbd>P</kbd>: タグをpush <kbd>P</kbd>: タグをpush
<kbd>n</kbd>: タグを作成 <kbd>n</kbd>: タグを作成
<kbd>g</kbd>: View reset options <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>&lt;c-y&gt;</kbd>: Pull RequestのURLをクリップボードにコピー
<kbd>c</kbd>: Checkout by name <kbd>c</kbd>: Checkout by name
<kbd>F</kbd>: Force checkout <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>r</kbd>: Rebase checked-out branch onto this branch
<kbd>M</kbd>: 現在のブランチにマージ <kbd>M</kbd>: 現在のブランチにマージ
<kbd>f</kbd>: Fast-forward this branch from its upstream <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>n</kbd>: 新しいブランチを作成
<kbd>M</kbd>: 現在のブランチにマージ <kbd>M</kbd>: 現在のブランチにマージ
<kbd>r</kbd>: Rebase checked-out branch onto this branch <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>u</kbd>: Set as upstream of checked-out branch
<kbd>g</kbd>: View reset options <kbd>g</kbd>: View reset options
<kbd>w</kbd>: View worktree options <kbd>w</kbd>: View worktree options

View File

@ -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>&lt;c-y&gt;</kbd>: 풀 리퀘스트 URL을 클립보드에 복사
<kbd>c</kbd>: 이름으로 체크아웃 <kbd>c</kbd>: 이름으로 체크아웃
<kbd>F</kbd>: 강제 체크아웃 <kbd>F</kbd>: 강제 체크아웃
<kbd>d</kbd>: 브랜치 삭제 <kbd>d</kbd>: View delete options
<kbd>r</kbd>: 체크아웃된 브랜치를 이 브랜치에 리베이스 <kbd>r</kbd>: 체크아웃된 브랜치를 이 브랜치에 리베이스
<kbd>M</kbd>: 현재 브랜치에 병합 <kbd>M</kbd>: 현재 브랜치에 병합
<kbd>f</kbd>: Fast-forward this branch from its upstream <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>n</kbd>: 새 브랜치 생성
<kbd>M</kbd>: 현재 브랜치에 병합 <kbd>M</kbd>: 현재 브랜치에 병합
<kbd>r</kbd>: 체크아웃된 브랜치를 이 브랜치에 리베이스 <kbd>r</kbd>: 체크아웃된 브랜치를 이 브랜치에 리베이스
<kbd>d</kbd>: 브랜치 삭제 <kbd>d</kbd>: Delete remote tag
<kbd>u</kbd>: Set as upstream of checked-out branch <kbd>u</kbd>: Set as upstream of checked-out branch
<kbd>g</kbd>: View reset options <kbd>g</kbd>: View reset options
<kbd>w</kbd>: View worktree 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> <pre>
<kbd>&lt;space&gt;</kbd>: 체크아웃 <kbd>&lt;space&gt;</kbd>: 체크아웃
<kbd>d</kbd>: 태그 삭제 <kbd>d</kbd>: View delete options
<kbd>P</kbd>: 태그를 push <kbd>P</kbd>: 태그를 push
<kbd>n</kbd>: 태그를 생성 <kbd>n</kbd>: 태그를 생성
<kbd>g</kbd>: View reset options <kbd>g</kbd>: View reset options

View File

@ -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>&lt;c-y&gt;</kbd>: Kopieer de URL van het pull-verzoek naar het klembord
<kbd>c</kbd>: Uitchecken bij naam <kbd>c</kbd>: Uitchecken bij naam
<kbd>F</kbd>: Forceer checkout <kbd>F</kbd>: Forceer checkout
<kbd>d</kbd>: Verwijder branch <kbd>d</kbd>: View delete options
<kbd>r</kbd>: Rebase branch <kbd>r</kbd>: Rebase branch
<kbd>M</kbd>: Merge in met huidige checked out branch <kbd>M</kbd>: Merge in met huidige checked out branch
<kbd>f</kbd>: Fast-forward deze branch vanaf zijn upstream <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>n</kbd>: Nieuwe branch
<kbd>M</kbd>: Merge in met huidige checked out branch <kbd>M</kbd>: Merge in met huidige checked out branch
<kbd>r</kbd>: Rebase 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>u</kbd>: Stel in als upstream van uitgecheckte branch
<kbd>g</kbd>: Bekijk reset opties <kbd>g</kbd>: Bekijk reset opties
<kbd>w</kbd>: View worktree 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> <pre>
<kbd>&lt;space&gt;</kbd>: Uitchecken <kbd>&lt;space&gt;</kbd>: Uitchecken
<kbd>d</kbd>: Verwijder tag <kbd>d</kbd>: View delete options
<kbd>P</kbd>: Push tag <kbd>P</kbd>: Push tag
<kbd>n</kbd>: Creëer tag <kbd>n</kbd>: Creëer tag
<kbd>g</kbd>: Bekijk reset opties <kbd>g</kbd>: Bekijk reset opties

View File

@ -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>&lt;c-y&gt;</kbd>: Skopiuj adres URL żądania pobrania do schowka
<kbd>c</kbd>: Przełącz używając nazwy <kbd>c</kbd>: Przełącz używając nazwy
<kbd>F</kbd>: Wymuś przełączenie <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>r</kbd>: Zmiana bazy gałęzi
<kbd>M</kbd>: Scal do obecnej gałęzi <kbd>M</kbd>: Scal do obecnej gałęzi
<kbd>f</kbd>: Fast-forward this branch from its upstream <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>n</kbd>: Nowa gałąź
<kbd>M</kbd>: Scal do obecnej gałęzi <kbd>M</kbd>: Scal do obecnej gałęzi
<kbd>r</kbd>: Zmiana bazy 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>u</kbd>: Set as upstream of checked-out branch
<kbd>g</kbd>: Wyświetl opcje resetu <kbd>g</kbd>: Wyświetl opcje resetu
<kbd>w</kbd>: View worktree options <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> <pre>
<kbd>&lt;space&gt;</kbd>: Przełącz <kbd>&lt;space&gt;</kbd>: Przełącz
<kbd>d</kbd>: Delete tag <kbd>d</kbd>: View delete options
<kbd>P</kbd>: Push tag <kbd>P</kbd>: Push tag
<kbd>n</kbd>: Create tag <kbd>n</kbd>: Create tag
<kbd>g</kbd>: Wyświetl opcje resetu <kbd>g</kbd>: Wyświetl opcje resetu

View File

@ -181,7 +181,7 @@ _Связки клавиш_
<kbd>&lt;c-y&gt;</kbd>: Скопировать URL запроса на принятие изменений в буфер обмена <kbd>&lt;c-y&gt;</kbd>: Скопировать URL запроса на принятие изменений в буфер обмена
<kbd>c</kbd>: Переключить по названию <kbd>c</kbd>: Переключить по названию
<kbd>F</kbd>: Принудительное переключение <kbd>F</kbd>: Принудительное переключение
<kbd>d</kbd>: Удалить ветку <kbd>d</kbd>: View delete options
<kbd>r</kbd>: Перебазировать переключённую ветку на эту ветку <kbd>r</kbd>: Перебазировать переключённую ветку на эту ветку
<kbd>M</kbd>: Слияние с текущей переключённой веткой <kbd>M</kbd>: Слияние с текущей переключённой веткой
<kbd>f</kbd>: Перемотать эту ветку вперёд из её upstream-ветки <kbd>f</kbd>: Перемотать эту ветку вперёд из её upstream-ветки
@ -277,7 +277,7 @@ _Связки клавиш_
<pre> <pre>
<kbd>&lt;space&gt;</kbd>: Переключить <kbd>&lt;space&gt;</kbd>: Переключить
<kbd>d</kbd>: Удалить тег <kbd>d</kbd>: View delete options
<kbd>P</kbd>: Отправить тег <kbd>P</kbd>: Отправить тег
<kbd>n</kbd>: Создать тег <kbd>n</kbd>: Создать тег
<kbd>g</kbd>: Просмотреть параметры сброса <kbd>g</kbd>: Просмотреть параметры сброса
@ -294,7 +294,7 @@ _Связки клавиш_
<kbd>n</kbd>: Новая ветка <kbd>n</kbd>: Новая ветка
<kbd>M</kbd>: Слияние с текущей переключённой веткой <kbd>M</kbd>: Слияние с текущей переключённой веткой
<kbd>r</kbd>: Перебазировать переключённую ветку на эту ветку <kbd>r</kbd>: Перебазировать переключённую ветку на эту ветку
<kbd>d</kbd>: Удалить ветку <kbd>d</kbd>: Delete remote tag
<kbd>u</kbd>: Установить как upstream-ветку переключённую ветку <kbd>u</kbd>: Установить как upstream-ветку переключённую ветку
<kbd>g</kbd>: Просмотреть параметры сброса <kbd>g</kbd>: Просмотреть параметры сброса
<kbd>w</kbd>: View worktree options <kbd>w</kbd>: View worktree options

View File

@ -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>&lt;c-y&gt;</kbd>: 将抓取请求 URL 复制到剪贴板
<kbd>c</kbd>: 按名称检出 <kbd>c</kbd>: 按名称检出
<kbd>F</kbd>: 强制检出 <kbd>F</kbd>: 强制检出
<kbd>d</kbd>: 删除分支 <kbd>d</kbd>: View delete options
<kbd>r</kbd>: 将已检出的分支变基到该分支 <kbd>r</kbd>: 将已检出的分支变基到该分支
<kbd>M</kbd>: 合并到当前检出的分支 <kbd>M</kbd>: 合并到当前检出的分支
<kbd>f</kbd>: 从上游快进此分支 <kbd>f</kbd>: 从上游快进此分支
@ -234,7 +234,7 @@ _Legend: `<c-b>` means ctrl+b, `<a-b>` means alt+b, `B` means shift+b_
<pre> <pre>
<kbd>&lt;space&gt;</kbd>: 检出 <kbd>&lt;space&gt;</kbd>: 检出
<kbd>d</kbd>: 删除标签 <kbd>d</kbd>: View delete options
<kbd>P</kbd>: 推送标签 <kbd>P</kbd>: 推送标签
<kbd>n</kbd>: 创建标签 <kbd>n</kbd>: 创建标签
<kbd>g</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>n</kbd>: 新分支
<kbd>M</kbd>: 合并到当前检出的分支 <kbd>M</kbd>: 合并到当前检出的分支
<kbd>r</kbd>: 将已检出的分支变基到该分支 <kbd>r</kbd>: 将已检出的分支变基到该分支
<kbd>d</kbd>: 删除分支 <kbd>d</kbd>: Delete remote tag
<kbd>u</kbd>: 设置为检出分支的上游 <kbd>u</kbd>: 设置为检出分支的上游
<kbd>g</kbd>: 查看重置选项 <kbd>g</kbd>: 查看重置选项
<kbd>w</kbd>: View worktree options <kbd>w</kbd>: View worktree options

View File

@ -256,7 +256,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
<kbd>&lt;c-y&gt;</kbd>: 複製拉取請求的 URL 到剪貼板 <kbd>&lt;c-y&gt;</kbd>: 複製拉取請求的 URL 到剪貼板
<kbd>c</kbd>: 根據名稱檢出 <kbd>c</kbd>: 根據名稱檢出
<kbd>F</kbd>: 強制檢出 <kbd>F</kbd>: 強制檢出
<kbd>d</kbd>: 刪除分支 <kbd>d</kbd>: View delete options
<kbd>r</kbd>: 將已檢出的分支變基至此分支 <kbd>r</kbd>: 將已檢出的分支變基至此分支
<kbd>M</kbd>: 合併到當前檢出的分支 <kbd>M</kbd>: 合併到當前檢出的分支
<kbd>f</kbd>: 從上游快進此分支 <kbd>f</kbd>: 從上游快進此分支
@ -273,7 +273,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
<pre> <pre>
<kbd>&lt;space&gt;</kbd>: 檢出 <kbd>&lt;space&gt;</kbd>: 檢出
<kbd>d</kbd>: 刪除標籤 <kbd>d</kbd>: View delete options
<kbd>P</kbd>: 推送標籤 <kbd>P</kbd>: 推送標籤
<kbd>n</kbd>: 建立標籤 <kbd>n</kbd>: 建立標籤
<kbd>g</kbd>: 檢視重設選項 <kbd>g</kbd>: 檢視重設選項
@ -344,7 +344,7 @@ _說明:`<c-b>` 表示 Ctrl+B、`<a-b>` 表示 Alt+B,`B`表示 Shift+B_
<kbd>n</kbd>: 新分支 <kbd>n</kbd>: 新分支
<kbd>M</kbd>: 合併到當前檢出的分支 <kbd>M</kbd>: 合併到當前檢出的分支
<kbd>r</kbd>: 將已檢出的分支變基至此分支 <kbd>r</kbd>: 將已檢出的分支變基至此分支
<kbd>d</kbd>: 刪除分支 <kbd>d</kbd>: Delete remote tag
<kbd>u</kbd>: 將此分支設為當前分支之上游 <kbd>u</kbd>: 將此分支設為當前分支之上游
<kbd>g</kbd>: 檢視重設選項 <kbd>g</kbd>: 檢視重設選項
<kbd>w</kbd>: View worktree options <kbd>w</kbd>: View worktree options

View File

@ -85,8 +85,8 @@ func (self *BranchCommands) CurrentBranchName() (string, error) {
return "", err return "", err
} }
// Delete delete branch // LocalDelete delete branch locally
func (self *BranchCommands) Delete(branch string, force bool) error { func (self *BranchCommands) LocalDelete(branch string, force bool) error {
cmdArgs := NewGitCmd("branch"). cmdArgs := NewGitCmd("branch").
ArgIfElse(force, "-D", "-d"). ArgIfElse(force, "-D", "-d").
Arg(branch). Arg(branch).

View File

@ -93,7 +93,7 @@ func TestBranchDeleteBranch(t *testing.T) {
t.Run(s.testName, func(t *testing.T) { t.Run(s.testName, func(t *testing.T) {
instance := buildBranchCommands(commonDeps{runner: s.runner}) instance := buildBranchCommands(commonDeps{runner: s.runner})
s.test(instance.Delete("test", s.force)) s.test(instance.LocalDelete("test", s.force))
s.runner.CheckForMissingCalls() s.runner.CheckForMissingCalls()
}) })
} }

View File

@ -56,6 +56,14 @@ func (self *RemoteCommands) DeleteRemoteBranch(task gocui.Task, remoteName strin
return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).WithMutex(self.syncMutex).Run() 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 // CheckRemoteBranchExists Returns remote branch
func (self *RemoteCommands) CheckRemoteBranchExists(branchName string) bool { func (self *RemoteCommands) CheckRemoteBranchExists(branchName string) bool {
cmdArgs := NewGitCmd("show-ref"). cmdArgs := NewGitCmd("show-ref").

View File

@ -41,7 +41,7 @@ func (self *TagCommands) HasTag(tagName string) bool {
return self.cmd.New(cmdArgs).Run() == nil 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). cmdArgs := NewGitCmd("tag").Arg("-d", tagName).
ToArgv() ToArgv()

View File

@ -86,6 +86,7 @@ func (gui *Gui) resetHelpersAndControllers() {
Files: helpers.NewFilesHelper(helperCommon), Files: helpers.NewFilesHelper(helperCommon),
WorkingTree: helpers.NewWorkingTreeHelper(helperCommon, refsHelper, commitsHelper, gpgHelper), WorkingTree: helpers.NewWorkingTreeHelper(helperCommon, refsHelper, commitsHelper, gpgHelper),
Tags: helpers.NewTagsHelper(helperCommon, commitsHelper), Tags: helpers.NewTagsHelper(helperCommon, commitsHelper),
BranchesHelper: helpers.NewBranchesHelper(helperCommon),
GPG: helpers.NewGpgHelper(helperCommon), GPG: helpers.NewGpgHelper(helperCommon),
MergeAndRebase: rebaseHelper, MergeAndRebase: rebaseHelper,
MergeConflicts: mergeConflictsHelper, MergeConflicts: mergeConflictsHelper,

View File

@ -70,7 +70,8 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty
{ {
Key: opts.GetKey(opts.Config.Universal.Remove), Key: opts.GetKey(opts.Config.Universal.Remove),
Handler: self.checkSelectedAndReal(self.delete), Handler: self.checkSelectedAndReal(self.delete),
Description: self.c.Tr.DeleteBranch, Description: self.c.Tr.ViewDeleteOptions,
OpensMenu: true,
}, },
{ {
Key: opts.GetKey(opts.Config.Branches.RebaseBranch), 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}) 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 { func (self *BranchesController) checkedOutByOtherWorktree(branch *models.Branch) bool {
return git_commands.CheckedOutByOtherWorktree(branch, self.c.Model().Worktrees) 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 { func (self *BranchesController) localDelete(branch *models.Branch) error {
title := self.c.Tr.DeleteBranch if self.checkedOutByOtherWorktree(branch) {
var templateStr string return self.promptWorktreeBranchDelete(branch)
if force {
templateStr = self.c.Tr.ForceDeleteBranchMessage
} else {
templateStr = self.c.Tr.DeleteBranchMessage
} }
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( message := utils.ResolvePlaceholderString(
templateStr, self.c.Tr.ForceDeleteBranchMessage,
map[string]string{ map[string]string{
"selectedBranchName": selectedBranch.Name, "selectedBranchName": branch.Name,
}, },
) )
@ -390,19 +394,60 @@ func (self *BranchesController) deleteWithForce(selectedBranch *models.Branch, f
Title: title, Title: title,
Prompt: message, Prompt: message,
HandleConfirm: func() error { HandleConfirm: func() error {
self.c.LogAction(self.c.Tr.Actions.DeleteBranch) if err := self.c.Git().Branch.LocalDelete(branch.Name, true); err != nil {
if err := self.c.Git().Branch.Delete(selectedBranch.Name, force); err != nil { return self.c.ErrorMsg(err.Error())
errMessage := err.Error()
if !force && strings.Contains(errMessage, "git branch -D ") {
return self.deleteWithForce(selectedBranch, true)
}
return self.c.ErrorMsg(errMessage)
} }
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.BRANCHES}}) 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 { func (self *BranchesController) merge() error {
selectedBranchName := self.context().GetSelected().Name selectedBranchName := self.context().GetSelected().Name
return self.c.Helpers().MergeAndRebase.MergeRefIntoCheckedOutBranch(selectedBranchName) return self.c.Helpers().MergeAndRebase.MergeRefIntoCheckedOutBranch(selectedBranchName)

View 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}})
})
},
})
}

View File

@ -22,6 +22,7 @@ type Helpers struct {
Suggestions *SuggestionsHelper Suggestions *SuggestionsHelper
Files *FilesHelper Files *FilesHelper
WorkingTree *WorkingTreeHelper WorkingTree *WorkingTreeHelper
BranchesHelper *BranchesHelper
Tags *TagsHelper Tags *TagsHelper
MergeAndRebase *MergeAndRebaseHelper MergeAndRebase *MergeAndRebaseHelper
MergeConflicts *MergeConflictsHelper MergeConflicts *MergeConflictsHelper

View File

@ -1,10 +1,8 @@
package controllers package controllers
import ( import (
"fmt"
"strings" "strings"
"github.com/jesseduffield/gocui"
"github.com/jesseduffield/lazygit/pkg/commands/models" "github.com/jesseduffield/lazygit/pkg/commands/models"
"github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/context"
"github.com/jesseduffield/lazygit/pkg/gui/types" "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), Key: opts.GetKey(opts.Config.Universal.Remove),
Handler: self.checkSelected(self.delete), Handler: self.checkSelected(self.delete),
Description: self.c.Tr.DeleteBranch, Description: self.c.Tr.DeleteRemoteTag,
}, },
{ {
Key: opts.GetKey(opts.Config.Branches.SetUpstream), 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 { func (self *RemoteBranchesController) delete(selectedBranch *models.RemoteBranch) error {
message := fmt.Sprintf("%s '%s'?", self.c.Tr.DeleteRemoteBranchMessage, selectedBranch.FullName()) return self.c.Helpers().BranchesHelper.ConfirmDeleteRemote(selectedBranch.RemoteName, selectedBranch.Name)
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}})
})
},
})
} }
func (self *RemoteBranchesController) merge(selectedBranch *models.RemoteBranch) error { func (self *RemoteBranchesController) merge(selectedBranch *models.RemoteBranch) error {

View File

@ -34,7 +34,8 @@ func (self *TagsController) GetKeybindings(opts types.KeybindingsOpts) []*types.
{ {
Key: opts.GetKey(opts.Config.Universal.Remove), Key: opts.GetKey(opts.Config.Universal.Remove),
Handler: self.withSelectedTag(self.delete), Handler: self.withSelectedTag(self.delete),
Description: self.c.Tr.DeleteTag, Description: self.c.Tr.ViewDeleteOptions,
OpensMenu: true,
}, },
{ {
Key: opts.GetKey(opts.Config.Branches.PushTag), 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) return self.c.PushContext(self.c.Contexts().Branches)
} }
func (self *TagsController) delete(tag *models.Tag) error { func (self *TagsController) localDelete(tag *models.Tag) error {
prompt := utils.ResolvePlaceholderString( return self.c.WithWaitingStatus(self.c.Tr.DeletingStatus, func(gocui.Task) error {
self.c.Tr.DeleteTagPrompt, 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{ map[string]string{
"tagName": tag.Name, "tagName": tag.Name,
}, },
) )
return self.c.Confirm(types.ConfirmOpts{ return self.c.Prompt(types.PromptOpts{
Title: self.c.Tr.DeleteTagTitle, Title: title,
Prompt: prompt, InitialContent: "origin",
HandleConfirm: func() error { FindSuggestionsFunc: self.c.Helpers().Suggestions.GetRemoteSuggestionsFunc(),
self.c.LogAction(self.c.Tr.Actions.DeleteTag) HandleConfirm: func(upstream string) error {
if err := self.c.Git().Tag.Delete(tag.Name); err != nil { confirmTitle := utils.ResolvePlaceholderString(
return self.c.Error(err) self.c.Tr.DeleteTagTitle,
} map[string]string{
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC, Scope: []types.RefreshableView{types.COMMITS, types.TAGS}}) "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 { func (self *TagsController) push(tag *models.Tag) error {
title := utils.ResolvePlaceholderString( title := utils.ResolvePlaceholderString(
self.c.Tr.PushTagTitle, self.c.Tr.PushTagTitle,

View File

@ -82,8 +82,6 @@ func chineseTranslationSet() TranslationSet {
BranchName: "分支名称", BranchName: "分支名称",
NewBranchNameBranchOff: "新分支名称(基于 {{.branchName}})", NewBranchNameBranchOff: "新分支名称(基于 {{.branchName}})",
CantDeleteCheckOutBranch: "您不能删除已检出的分支!", CantDeleteCheckOutBranch: "您不能删除已检出的分支!",
DeleteBranch: "删除分支",
DeleteBranchMessage: "您确定要删除分支 {{.selectedBranchName}} 吗?",
ForceDeleteBranchMessage: "{{.selectedBranchName}} 还没有被完全合并。您确定要删除它吗?", ForceDeleteBranchMessage: "{{.selectedBranchName}} 还没有被完全合并。您确定要删除它吗?",
RebaseBranch: "将已检出的分支变基到该分支", RebaseBranch: "将已检出的分支变基到该分支",
CantRebaseOntoSelf: "您不能将分支变基到其自身", CantRebaseOntoSelf: "您不能将分支变基到其自身",
@ -309,9 +307,6 @@ func chineseTranslationSet() TranslationSet {
TagMessageTitle: "标签消息", TagMessageTitle: "标签消息",
AnnotatedTag: "附注标签", AnnotatedTag: "附注标签",
LightweightTag: "轻量标签", LightweightTag: "轻量标签",
DeleteTag: "删除标签",
DeleteTagTitle: "删除标签",
DeleteTagPrompt: "您确定要删除标签 {{.tagName}} 吗?",
PushTagTitle: "将 {{.tagName}} 推送到远程仓库:", PushTagTitle: "将 {{.tagName}} 推送到远程仓库:",
PushTag: "推送标签", PushTag: "推送标签",
CreateTag: "创建标签", CreateTag: "创建标签",
@ -457,7 +452,6 @@ func chineseTranslationSet() TranslationSet {
CheckoutTag: "检出标签", CheckoutTag: "检出标签",
CheckoutBranch: "检出分支", CheckoutBranch: "检出分支",
ForceCheckoutBranch: "强制检出分支", ForceCheckoutBranch: "强制检出分支",
DeleteBranch: "删除分支",
Merge: "合并", Merge: "合并",
RebaseBranch: "变基分支", RebaseBranch: "变基分支",
RenameBranch: "重命名分支", RenameBranch: "重命名分支",
@ -521,7 +515,6 @@ func chineseTranslationSet() TranslationSet {
BulkUpdateSubmodules: "批量更新子模块", BulkUpdateSubmodules: "批量更新子模块",
BulkDeinitialiseSubmodules: "批量取消初始化子模块", BulkDeinitialiseSubmodules: "批量取消初始化子模块",
UpdateSubmodule: "更新子模块", UpdateSubmodule: "更新子模块",
DeleteTag: "删除标签",
PushTag: "推送标签", PushTag: "推送标签",
NukeWorkingTree: "Nuke 工作树", NukeWorkingTree: "Nuke 工作树",
DiscardUnstagedFileChanges: "放弃未暂存的文件更改", DiscardUnstagedFileChanges: "放弃未暂存的文件更改",

View File

@ -48,8 +48,6 @@ func dutchTranslationSet() TranslationSet {
BranchName: "Branch naam", BranchName: "Branch naam",
NewBranchNameBranchOff: "Nieuw branch naam (Branch is afgeleid van '{{.branchName}}')", NewBranchNameBranchOff: "Nieuw branch naam (Branch is afgeleid van '{{.branchName}}')",
CantDeleteCheckOutBranch: "Je kan een uitgecheckte branch niet verwijderen!", 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?", ForceDeleteBranchMessage: "Weet je zeker dat je branch '{{.selectedBranchName}}' geforceerd wil verwijderen?",
RebaseBranch: "Rebase branch", RebaseBranch: "Rebase branch",
CantRebaseOntoSelf: "Je kan niet een branch rebasen op zichzelf", 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", SetUpstreamMessage: "Weet je zeker dat je de upstream branch van '{{.checkedOut}}' naar '{{.selected}}' wilt zetten",
EditRemote: "Wijzig remote", EditRemote: "Wijzig remote",
TagCommit: "Tag commit", TagCommit: "Tag commit",
TagNameTitle: "Tag naam", TagNameTitle: "Tag naam:",
DeleteTag: "Verwijder tag",
DeleteTagTitle: "Verwijder tag",
DeleteTagPrompt: "Weet je zeker dat je '{{.tagName}}' wil verwijderen?",
PushTagTitle: "Remote om tag '{{.tagName}}' te pushen naar:", PushTagTitle: "Remote om tag '{{.tagName}}' te pushen naar:",
PushTag: "Push tag", PushTag: "Push tag",
CreateTag: "Creëer tag", CreateTag: "Creëer tag",

View File

@ -68,8 +68,11 @@ type TranslationSet struct {
BranchName string BranchName string
NewBranchNameBranchOff string NewBranchNameBranchOff string
CantDeleteCheckOutBranch string CantDeleteCheckOutBranch string
DeleteBranch string DeleteBranchTitle string
DeleteBranchMessage string DeleteLocalBranch string
DeleteRemoteBranchOption string
DeleteRemoteBranchPrompt string
ForceDeleteBranchTitle string
ForceDeleteBranchMessage string ForceDeleteBranchMessage string
RebaseBranch string RebaseBranch string
CantRebaseOntoSelf string CantRebaseOntoSelf string
@ -292,6 +295,7 @@ type TranslationSet struct {
DiscardUntrackedFiles string DiscardUntrackedFiles string
DiscardStagedChanges string DiscardStagedChanges string
HardReset string HardReset string
ViewDeleteOptions string
ViewResetOptions string ViewResetOptions string
CreateFixupCommit string CreateFixupCommit string
CreateFixupCommitDescription string CreateFixupCommitDescription string
@ -352,9 +356,12 @@ type TranslationSet struct {
TagMessageTitle string TagMessageTitle string
LightweightTag string LightweightTag string
AnnotatedTag string AnnotatedTag string
DeleteTag string
DeleteTagTitle string DeleteTagTitle string
DeleteTagPrompt string DeleteLocalTag string
DeleteRemoteTag string
SelectRemoteTagUpstream string
DeleteRemoteTagPrompt string
RemoteTagDeletedMessage string
PushTagTitle string PushTagTitle string
PushTag string PushTag string
CreateTag string CreateTag string
@ -633,6 +640,7 @@ type Actions struct {
CheckoutTag string CheckoutTag string
CheckoutBranch string CheckoutBranch string
ForceCheckoutBranch string ForceCheckoutBranch string
DeleteLocalBranch string
DeleteBranch string DeleteBranch string
Merge string Merge string
RebaseBranch string RebaseBranch string
@ -715,7 +723,8 @@ type Actions struct {
UpdateSubmodule string UpdateSubmodule string
CreateLightweightTag string CreateLightweightTag string
CreateAnnotatedTag string CreateAnnotatedTag string
DeleteTag string DeleteLocalTag string
DeleteRemoteTag string
PushTag string PushTag string
NukeWorkingTree string NukeWorkingTree string
DiscardUnstagedFileChanges string DiscardUnstagedFileChanges string
@ -829,8 +838,11 @@ func EnglishTranslationSet() TranslationSet {
BranchName: "Branch name", BranchName: "Branch name",
NewBranchNameBranchOff: "New branch name (branch is off of '{{.branchName}}')", NewBranchNameBranchOff: "New branch name (branch is off of '{{.branchName}}')",
CantDeleteCheckOutBranch: "You cannot delete the checked out branch!", CantDeleteCheckOutBranch: "You cannot delete the checked out branch!",
DeleteBranch: "Delete branch", DeleteBranchTitle: "Delete branch '{{.selectedBranchName}}'?",
DeleteBranchMessage: "Are you sure you want to delete the 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?", ForceDeleteBranchMessage: "'{{.selectedBranchName}}' is not fully merged. Are you sure you want to delete it?",
RebaseBranch: "Rebase checked-out branch onto this branch", RebaseBranch: "Rebase checked-out branch onto this branch",
CantRebaseOntoSelf: "You cannot rebase a branch onto itself", CantRebaseOntoSelf: "You cannot rebase a branch onto itself",
@ -1056,6 +1068,7 @@ func EnglishTranslationSet() TranslationSet {
DiscardUntrackedFiles: "Discard untracked files", DiscardUntrackedFiles: "Discard untracked files",
DiscardStagedChanges: "Discard staged changes", DiscardStagedChanges: "Discard staged changes",
HardReset: "Hard reset", HardReset: "Hard reset",
ViewDeleteOptions: "View delete options",
ViewResetOptions: `View reset options`, ViewResetOptions: `View reset options`,
CreateFixupCommitDescription: `Create fixup commit for this commit`, CreateFixupCommitDescription: `Create fixup commit for this commit`,
SquashAboveCommits: `Squash all 'fixup!' commits above selected commit (autosquash)`, SquashAboveCommits: `Squash all 'fixup!' commits above selected commit (autosquash)`,
@ -1102,7 +1115,7 @@ func EnglishTranslationSet() TranslationSet {
EditRemoteUrl: `Enter updated remote url for {{.remoteName}}:`, EditRemoteUrl: `Enter updated remote url for {{.remoteName}}:`,
RemoveRemote: `Remove remote`, RemoveRemote: `Remove remote`,
RemoveRemotePrompt: "Are you sure you want to 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", DeleteRemoteBranchMessage: "Are you sure you want to delete remote branch",
SetAsUpstream: "Set as upstream of checked-out branch", SetAsUpstream: "Set as upstream of checked-out branch",
SetUpstream: "Set upstream of selected branch", SetUpstream: "Set upstream of selected branch",
@ -1116,9 +1129,12 @@ func EnglishTranslationSet() TranslationSet {
TagMessageTitle: "Tag description", TagMessageTitle: "Tag description",
AnnotatedTag: "Annotated tag", AnnotatedTag: "Annotated tag",
LightweightTag: "Lightweight tag", LightweightTag: "Lightweight tag",
DeleteTag: "Delete tag", DeleteTagTitle: "Delete tag '{{.tagName}}'?",
DeleteTagTitle: "Delete tag", DeleteLocalTag: "Delete local tag",
DeleteTagPrompt: "Are you sure you want to delete tag '{{.tagName}}'?", 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:", PushTagTitle: "Remote to push tag '{{.tagName}}' to:",
PushTag: "Push tag", PushTag: "Push tag",
CreateTag: "Create tag", CreateTag: "Create tag",
@ -1355,6 +1371,7 @@ func EnglishTranslationSet() TranslationSet {
CheckoutTag: "Checkout tag", CheckoutTag: "Checkout tag",
CheckoutBranch: "Checkout branch", CheckoutBranch: "Checkout branch",
ForceCheckoutBranch: "Force checkout branch", ForceCheckoutBranch: "Force checkout branch",
DeleteLocalBranch: "Delete local branch",
DeleteBranch: "Delete branch", DeleteBranch: "Delete branch",
Merge: "Merge", Merge: "Merge",
RebaseBranch: "Rebase branch", RebaseBranch: "Rebase branch",
@ -1436,7 +1453,8 @@ func EnglishTranslationSet() TranslationSet {
BulkUpdateSubmodules: "Bulk update submodules", BulkUpdateSubmodules: "Bulk update submodules",
BulkDeinitialiseSubmodules: "Bulk deinitialise submodules", BulkDeinitialiseSubmodules: "Bulk deinitialise submodules",
UpdateSubmodule: "Update submodule", UpdateSubmodule: "Update submodule",
DeleteTag: "Delete tag", DeleteLocalTag: "Delete local tag",
DeleteRemoteTag: "Delete remote tag",
PushTag: "Push tag", PushTag: "Push tag",
NukeWorkingTree: "Nuke working tree", NukeWorkingTree: "Nuke working tree",
DiscardUnstagedFileChanges: "Discard unstaged file changes", DiscardUnstagedFileChanges: "Discard unstaged file changes",

View File

@ -73,9 +73,6 @@ func japaneseTranslationSet() TranslationSet {
BranchName: "ブランチ名", BranchName: "ブランチ名",
NewBranchNameBranchOff: "新規ブランチ名 ('{{.branchName}}' に作成)", NewBranchNameBranchOff: "新規ブランチ名 ('{{.branchName}}' に作成)",
CantDeleteCheckOutBranch: "チェックアウト中のブランチは削除できません!", CantDeleteCheckOutBranch: "チェックアウト中のブランチは削除できません!",
DeleteBranch: "ブランチを削除",
DeleteBranchMessage: "ブランチ '{{.selectedBranchName}}' を削除します。よろしいですか?",
ForceDeleteBranchMessage: "'{{.selectedBranchName}}' はマージされていません。本当に削除しますか?",
// LcRebaseBranch: "Rebase checked-out branch onto this branch", // LcRebaseBranch: "Rebase checked-out branch onto this branch",
CantRebaseOntoSelf: "ブランチを自分自身にリベースすることはできません。", CantRebaseOntoSelf: "ブランチを自分自身にリベースすることはできません。",
CantMergeBranchIntoItself: "ブランチを自分自身にマージすることはできません。", CantMergeBranchIntoItself: "ブランチを自分自身にマージすることはできません。",
@ -319,9 +316,6 @@ func japaneseTranslationSet() TranslationSet {
TagMessageTitle: "タグメッセージ", TagMessageTitle: "タグメッセージ",
AnnotatedTag: "注釈付きタグ", AnnotatedTag: "注釈付きタグ",
LightweightTag: "軽量タグ", LightweightTag: "軽量タグ",
DeleteTag: "タグを削除",
DeleteTagTitle: "タグを削除",
DeleteTagPrompt: "タグ '{{.tagName}}' を削除します。よろしいですか?",
PushTagTitle: "リモートにタグ '{{.tagName}}' をpush", PushTagTitle: "リモートにタグ '{{.tagName}}' をpush",
PushTag: "タグをpush", PushTag: "タグをpush",
CreateTag: "タグを作成", CreateTag: "タグを作成",
@ -554,7 +548,6 @@ func japaneseTranslationSet() TranslationSet {
BulkUpdateSubmodules: "サブモジュールを一括更新", BulkUpdateSubmodules: "サブモジュールを一括更新",
// BulkDeinitialiseSubmodules: "Bulk deinitialise submodules", // BulkDeinitialiseSubmodules: "Bulk deinitialise submodules",
UpdateSubmodule: "サブモジュールを更新", UpdateSubmodule: "サブモジュールを更新",
DeleteTag: "タグを削除",
PushTag: "タグをpush", PushTag: "タグをpush",
// NukeWorkingTree: "Nuke working tree", // NukeWorkingTree: "Nuke working tree",
// DiscardUnstagedFileChanges: "Discard unstaged file changes", // DiscardUnstagedFileChanges: "Discard unstaged file changes",

View File

@ -72,8 +72,6 @@ func koreanTranslationSet() TranslationSet {
BranchName: "브랜치 이름", BranchName: "브랜치 이름",
NewBranchNameBranchOff: "새 브랜치 이름 (branch is off of '{{.branchName}}')", NewBranchNameBranchOff: "새 브랜치 이름 (branch is off of '{{.branchName}}')",
CantDeleteCheckOutBranch: "체크아웃하는 브랜치는 삭제할 수 없습니다!", CantDeleteCheckOutBranch: "체크아웃하는 브랜치는 삭제할 수 없습니다!",
DeleteBranch: "브랜치 삭제",
DeleteBranchMessage: "정말로 브랜치 '{{.selectedBranchName}}' 를 삭제하시겠습니까?",
ForceDeleteBranchMessage: "'{{.selectedBranchName}}'는 완전히 병합되지 않았습니다. 정말 삭제하시겠습니까?", ForceDeleteBranchMessage: "'{{.selectedBranchName}}'는 완전히 병합되지 않았습니다. 정말 삭제하시겠습니까?",
RebaseBranch: "체크아웃된 브랜치를 이 브랜치에 리베이스", RebaseBranch: "체크아웃된 브랜치를 이 브랜치에 리베이스",
CantRebaseOntoSelf: "브랜치를 자기 자신에게 리베이스할 수는 없습니다.", CantRebaseOntoSelf: "브랜치를 자기 자신에게 리베이스할 수는 없습니다.",
@ -314,9 +312,6 @@ func koreanTranslationSet() TranslationSet {
TagMessageTitle: "태그 메시지", TagMessageTitle: "태그 메시지",
AnnotatedTag: "Annotated tag", AnnotatedTag: "Annotated tag",
LightweightTag: "Lightweight tag", LightweightTag: "Lightweight tag",
DeleteTag: "태그 삭제",
DeleteTagTitle: "태그 삭제",
DeleteTagPrompt: "정말로 태그 '{{.tagName}}' 를 삭제하시겠습니까?",
PushTagTitle: "원격에 태그 '{{.tagName}}' 를 푸시", PushTagTitle: "원격에 태그 '{{.tagName}}' 를 푸시",
PushTag: "태그를 push", PushTag: "태그를 push",
CreateTag: "태그를 생성", CreateTag: "태그를 생성",
@ -478,7 +473,6 @@ func koreanTranslationSet() TranslationSet {
CheckoutTag: "태그 체크아웃", CheckoutTag: "태그 체크아웃",
CheckoutBranch: "브랜치 체크아웃", CheckoutBranch: "브랜치 체크아웃",
ForceCheckoutBranch: "브랜치 Force 체크아웃", ForceCheckoutBranch: "브랜치 Force 체크아웃",
DeleteBranch: "브랜치 삭제",
Merge: "병합", Merge: "병합",
RebaseBranch: "브랜치 리베이스", RebaseBranch: "브랜치 리베이스",
RenameBranch: "브랜치 이름 변경", RenameBranch: "브랜치 이름 변경",
@ -552,7 +546,6 @@ func koreanTranslationSet() TranslationSet {
BulkUpdateSubmodules: "Bulk update submodules", BulkUpdateSubmodules: "Bulk update submodules",
BulkDeinitialiseSubmodules: "Bulk deinitialise submodules", BulkDeinitialiseSubmodules: "Bulk deinitialise submodules",
UpdateSubmodule: "서브모듈 업데이트", UpdateSubmodule: "서브모듈 업데이트",
DeleteTag: "태그 삭제",
PushTag: "태그 푸시g", PushTag: "태그 푸시g",
NukeWorkingTree: "Nuke working tree", NukeWorkingTree: "Nuke working tree",
DiscardUnstagedFileChanges: "Unstaged 파일 변경사항 버리기", DiscardUnstagedFileChanges: "Unstaged 파일 변경사항 버리기",

View File

@ -43,8 +43,6 @@ func polishTranslationSet() TranslationSet {
BranchName: "Nazwa gałęzi", BranchName: "Nazwa gałęzi",
NewBranchNameBranchOff: "Nazwa nowej gałęzi (gałąź na bazie '{{.branchName}}')", NewBranchNameBranchOff: "Nazwa nowej gałęzi (gałąź na bazie '{{.branchName}}')",
CantDeleteCheckOutBranch: "Nie możesz usunąć obecnie przełączonej gałęzi!", 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}}'?", ForceDeleteBranchMessage: "Na pewno wymusić usunięcie gałęzi '{{.selectedBranchName}}'?",
RebaseBranch: "Zmiana bazy gałęzi", RebaseBranch: "Zmiana bazy gałęzi",
CantRebaseOntoSelf: "Nie możesz zmienić bazy gałęzi na nią samą", CantRebaseOntoSelf: "Nie możesz zmienić bazy gałęzi na nią samą",

View File

@ -91,8 +91,6 @@ func RussianTranslationSet() TranslationSet {
BranchName: "Название ветки", BranchName: "Название ветки",
NewBranchNameBranchOff: "Название новой ветки (Ветка с '{{.branchName}}')", NewBranchNameBranchOff: "Название новой ветки (Ветка с '{{.branchName}}')",
CantDeleteCheckOutBranch: "Невозможно удалить переключённую ветку!", CantDeleteCheckOutBranch: "Невозможно удалить переключённую ветку!",
DeleteBranch: "Удалить ветку",
DeleteBranchMessage: "Вы уверены, что хотите удалить ветку '{{.selectedBranchName}}'?",
ForceDeleteBranchMessage: "'{{.selectedBranchName}}' не полностью слилась. Вы уверены, что хотите удалить его?", ForceDeleteBranchMessage: "'{{.selectedBranchName}}' не полностью слилась. Вы уверены, что хотите удалить его?",
RebaseBranch: "Перебазировать переключённую ветку на эту ветку", RebaseBranch: "Перебазировать переключённую ветку на эту ветку",
CantRebaseOntoSelf: "Невозможно перебазировать ветку на себя", CantRebaseOntoSelf: "Невозможно перебазировать ветку на себя",
@ -375,9 +373,7 @@ func RussianTranslationSet() TranslationSet {
TagMessageTitle: "Сообщения тега", TagMessageTitle: "Сообщения тега",
AnnotatedTag: "Аннотированный тег", AnnotatedTag: "Аннотированный тег",
LightweightTag: "Легковесный тег", LightweightTag: "Легковесный тег",
DeleteTag: "Удалить тег",
DeleteTagTitle: "Удалить тег", DeleteTagTitle: "Удалить тег",
DeleteTagPrompt: "Вы уверены, что хотите удалить тег '{{.tagName}}'?",
PushTagTitle: "Удалённый репозитории для отправки тега '{{.tagName}}' в:", PushTagTitle: "Удалённый репозитории для отправки тега '{{.tagName}}' в:",
PushTag: "Отправить тег", PushTag: "Отправить тег",
CreateTag: "Создать тег", CreateTag: "Создать тег",
@ -647,7 +643,6 @@ func RussianTranslationSet() TranslationSet {
BulkUpdateSubmodules: "Массовое обновление подмодулей", BulkUpdateSubmodules: "Массовое обновление подмодулей",
BulkDeinitialiseSubmodules: "Массовая деинициализация подмодулей", BulkDeinitialiseSubmodules: "Массовая деинициализация подмодулей",
UpdateSubmodule: "Обновить подмодуль", UpdateSubmodule: "Обновить подмодуль",
DeleteTag: "Удалить тег",
PushTag: "Отправить тег", PushTag: "Отправить тег",
NukeWorkingTree: "Уничтожить рабочее дерево", NukeWorkingTree: "Уничтожить рабочее дерево",
DiscardUnstagedFileChanges: "Отменить непроиндексированные изменения файла", DiscardUnstagedFileChanges: "Отменить непроиндексированные изменения файла",

View File

@ -124,8 +124,6 @@ func traditionalChineseTranslationSet() TranslationSet {
BranchName: "分支名稱", BranchName: "分支名稱",
NewBranchNameBranchOff: "新的分支名稱 (根據 '{{.branchName}}' 分支創建)", NewBranchNameBranchOff: "新的分支名稱 (根據 '{{.branchName}}' 分支創建)",
CantDeleteCheckOutBranch: "你不能刪除已檢出的分支!", CantDeleteCheckOutBranch: "你不能刪除已檢出的分支!",
DeleteBranch: "刪除分支",
DeleteBranchMessage: "你確定要刪除 '{{.selectedBranchName}}' 分支嗎?",
ForceDeleteBranchMessage: "'{{.selectedBranchName}}' 分支尚未完全合併。你確定要刪除嗎?", ForceDeleteBranchMessage: "'{{.selectedBranchName}}' 分支尚未完全合併。你確定要刪除嗎?",
RebaseBranch: "將已檢出的分支變基至此分支", RebaseBranch: "將已檢出的分支變基至此分支",
CantRebaseOntoSelf: "你不能將分支變基至自己", CantRebaseOntoSelf: "你不能將分支變基至自己",
@ -402,9 +400,6 @@ func traditionalChineseTranslationSet() TranslationSet {
TagMessageTitle: "標籤訊息", TagMessageTitle: "標籤訊息",
AnnotatedTag: "附註標籤", AnnotatedTag: "附註標籤",
LightweightTag: "輕量標籤", LightweightTag: "輕量標籤",
DeleteTag: "刪除標籤",
DeleteTagTitle: "刪除標籤",
DeleteTagPrompt: "你確定要刪除 '{{.tagName}}' 標籤嗎?",
PushTagTitle: "推送標籤 '{{.tagName}}' 至遠端:", PushTagTitle: "推送標籤 '{{.tagName}}' 至遠端:",
PushTag: "推送標籤", PushTag: "推送標籤",
CreateTag: "建立標籤", CreateTag: "建立標籤",
@ -674,7 +669,6 @@ func traditionalChineseTranslationSet() TranslationSet {
BulkUpdateSubmodules: "批量更新子模塊", BulkUpdateSubmodules: "批量更新子模塊",
BulkDeinitialiseSubmodules: "批量取消初始化子模塊", BulkDeinitialiseSubmodules: "批量取消初始化子模塊",
UpdateSubmodule: "更新子模塊", UpdateSubmodule: "更新子模塊",
DeleteTag: "刪除標籤",
PushTag: "推送標籤", PushTag: "推送標籤",
NukeWorkingTree: "清空工作樹", NukeWorkingTree: "清空工作樹",
DiscardUnstagedFileChanges: "放棄未預存的檔案更改", DiscardUnstagedFileChanges: "放棄未預存的檔案更改",

View File

@ -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")) 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 { 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) { self.assertWithRetries(func() (bool, string) {
output, err := self.shell.runCommandWithOutput(cmdArgs) output, err := self.shell.runCommandWithOutput(cmdArgs)
if err != nil { if err != nil {
return false, fmt.Sprintf("Unexpected error running command: `%v`. Error: %s", cmdArgs, err.Error()) return false, fmt.Sprintf("Unexpected error running command: `%v`. Error: %s", cmdArgs, err.Error())
} }
actual := strings.TrimSpace(output) 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 return self

View File

@ -66,6 +66,12 @@ func (self *MenuDriver) Wait(milliseconds int) *MenuDriver {
return self return self
} }
func (self *MenuDriver) Tooltip(option *TextMatcher) *MenuDriver {
self.t.Views().Tooltip().Content(option)
return self
}
func (self *MenuDriver) checkNecessaryChecksCompleted() { func (self *MenuDriver) checkNecessaryChecksCompleted() {
if !self.hasCheckedTitle { if !self.hasCheckedTitle {
self.t.Fail("You must check the title of a menu popup by calling Title() before calling Confirm()/Cancel().") self.t.Fail("You must check the title of a menu popup by calling Title() before calling Confirm()/Cancel().")

View File

@ -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}) 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 // convenience method for creating a file and adding it
func (self *Shell) CreateFileAndAdd(fileName string, fileContents string) *Shell { func (self *Shell) CreateFileAndAdd(fileName string, fileContents string) *Shell {
return self. return self.

View File

@ -222,3 +222,7 @@ func (self *Views) Suggestions() *ViewDriver {
func (self *Views) Search() *ViewDriver { func (self *Views) Search() *ViewDriver {
return self.regularView("search") return self.regularView("search")
} }
func (self *Views) Tooltip() *ViewDriver {
return self.regularView("tooltip")
}

View File

@ -6,38 +6,110 @@ import (
) )
var Delete = NewIntegrationTest(NewIntegrationTestArgs{ 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{}, ExtraCmdArgs: []string{},
Skip: false, Skip: false,
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shell. shell.
CloneIntoRemote("origin").
EmptyCommit("blah"). EmptyCommit("blah").
NewBranch("branch-one"). 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) { Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Branches(). t.Views().Branches().
Focus(). Focus().
Lines( Lines(
MatchesRegexp(`\*.*branch-two`).IsSelected(), MatchesRegexp(`\*.*branch-three`).IsSelected(),
MatchesRegexp(`branch-two`),
MatchesRegexp(`branch-one`), MatchesRegexp(`branch-one`),
MatchesRegexp(`master`), MatchesRegexp(`master`),
). ).
Press(keys.Universal.Remove). Press(keys.Universal.Remove).
Tap(func() { 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(). SelectNextItem().
Press(keys.Universal.Remove). Press(keys.Universal.Remove).
Tap(func() { Tap(func() {
t.ExpectPopup().Confirmation(). t.ExpectPopup().
Title(Equals("Delete branch")). Menu().
Content(Contains("Are you sure you want to delete the branch 'branch-one'?")). 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() Confirm()
}). }).
Lines( 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(), MatchesRegexp(`master`).IsSelected(),
) )
}, },

View File

@ -12,6 +12,7 @@ var CrudAnnotated = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shell.EmptyCommit("initial commit") shell.EmptyCommit("initial commit")
shell.CloneIntoRemote("origin")
}, },
Run: func(t *TestDriver, keys config.KeybindingConfig) { Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Tags(). t.Views().Tags().
@ -31,11 +32,53 @@ var CrudAnnotated = NewIntegrationTest(NewIntegrationTestArgs{
Lines( Lines(
MatchesRegexp(`new-tag.*message`).IsSelected(), 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). Press(keys.Universal.Remove).
Tap(func() { Tap(func() {
t.ExpectPopup().Confirmation(). t.ExpectPopup().
Title(Equals("Delete tag")). Menu().
Content(Equals("Are you sure you want to delete tag 'new-tag'?")). 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() Confirm()
}). }).
IsEmpty(). IsEmpty().

View File

@ -12,6 +12,7 @@ var CrudLightweight = NewIntegrationTest(NewIntegrationTestArgs{
SetupConfig: func(config *config.AppConfig) {}, SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) { SetupRepo: func(shell *Shell) {
shell.EmptyCommit("initial commit") shell.EmptyCommit("initial commit")
shell.CloneIntoRemote("origin")
}, },
Run: func(t *TestDriver, keys config.KeybindingConfig) { Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Tags(). t.Views().Tags().
@ -36,11 +37,53 @@ var CrudLightweight = NewIntegrationTest(NewIntegrationTestArgs{
). ).
PressEscape() 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). Press(keys.Universal.Remove).
Tap(func() { Tap(func() {
t.ExpectPopup().Confirmation(). t.ExpectPopup().
Title(Equals("Delete tag")). Menu().
Content(Equals("Are you sure you want to delete tag 'new-tag'?")). 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() Confirm()
}). }).
IsEmpty() IsEmpty()

View File

@ -27,6 +27,13 @@ var DetachWorktreeFromBranch = NewIntegrationTest(NewIntegrationTestArgs{
). ).
NavigateToLine(Contains("newbranch")). NavigateToLine(Contains("newbranch")).
Press(keys.Universal.Remove). Press(keys.Universal.Remove).
Tap(func() {
t.ExpectPopup().
Menu().
Title(Equals("Delete branch 'newbranch'?")).
Select(Contains("Delete local branch")).
Confirm()
}).
Tap(func() { Tap(func() {
t.ExpectPopup().Menu(). t.ExpectPopup().Menu().
Title(Equals("Branch newbranch is checked out by worktree linked-worktree")). Title(Equals("Branch newbranch is checked out by worktree linked-worktree")).

View File

@ -28,6 +28,13 @@ var RemoveWorktreeFromBranch = NewIntegrationTest(NewIntegrationTestArgs{
). ).
NavigateToLine(Contains("newbranch")). NavigateToLine(Contains("newbranch")).
Press(keys.Universal.Remove). Press(keys.Universal.Remove).
Tap(func() {
t.ExpectPopup().
Menu().
Title(Equals("Delete branch 'newbranch'?")).
Select(Contains("Delete local branch")).
Confirm()
}).
Tap(func() { Tap(func() {
t.ExpectPopup().Menu(). t.ExpectPopup().Menu().
Title(Equals("Branch newbranch is checked out by worktree linked-worktree")). Title(Equals("Branch newbranch is checked out by worktree linked-worktree")).