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:
parent
c43830b027
commit
0df5cb1286
@ -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")).
|
||||
|
Loading…
x
Reference in New Issue
Block a user